Laravel Eloquent Database Validators Not Working In Slim 3 - php

I am developing in Slim 3. I decided for Eloquent as ORM and would like to use Illuminate validators in middleware to validate info that comes to my Controllers.
Validation rules that do not need to use database to validate work great but I am having trouble using database validators.
I do not get any errors it just does not pass when it should.
As far as I understand it I should create validator factory and then call make function. Example:
$v = $this->validatorFactory
->make($toCheck, $this->rules[$route], $this->messages);
if ($v->fails()) {....}
Since it works for all routes that do not need database I won't go here in any more detail. I think the problem is with how I add PressenceValidator to my factory.
I do it like this.
private function initiateValidatorFactory($dbConnectionSettings)
{
$validatorFactory = new ValidatorFactory(
new Translator(new FileLoader(new Filesystem(), "en"), "en"),
null);
$sqlConfig = $dbConnectionSettings['mysql'];
$dsn = 'mysql:host=' . $sqlConfig['host'] . ';port=' . $sqlConfig['port'] . ';dbname=' . $sqlConfig['database'];
$connection = new Connection(
new \PDO($dsn, $sqlConfig['username'], $sqlConfig['password']),
$sqlConfig['database'],
$sqlConfig['prefix']
);
// var_dump($connection->select('SELECT * FROM platform;'));
// die();
$resolver = new ConnectionResolver(['mysql' => $connection]);
// var_dump($resolver->hasConnection('mysql'));
// die();
// var_dump($resolver->connection('mysql'));
// die();
$verifier = new DatabasePresenceVerifier($resolver);
// $verifier->setConnection('mysql');
$validatorFactory->setPresenceVerifier($verifier);
$this->validatorFactory = $validatorFactory;
}
I would like to note that this raw SQL query which is commented out works at that point. That is why I don't think problem is with Connection class.
Notice how I created almost dummy FileLoader but I don't think I need it for my use case (or I might I am not sure).
All commented out checks look ok.
I tried googling and saw that people mention something about "booting eloquent". I tried to find where I could do that in my code but wasn't successful.
Last thing is I am missing is how I write my rules. Example rule is this:
'platformid' => 'exists:mysql.platform,platformid'
PS don't ask why we have column "platformid" in table "platform" =).
I am using illuminate/validation 5.5 and illuminate/database 5.5.
Thank you for your time and any help you can provide in advance.

I somehow figured it out. It is hacky but I think I can live with it now. I don't quite understand why this approach works but it does.
So I have database service provider like this:
$capsule = new Manager();
////////CONFIGURE MYSQL\\\\\\\
$sqlConfig = $pimple['settings']['db']['mysql'];
$capsule->addConnection([
'driver' => $sqlConfig['driver'],
'host' => $sqlConfig['host'],
'database' => $sqlConfig['database'],
'username' => $sqlConfig['username'],
'password' => $sqlConfig['password'],
'charset' => 'utf8',
'collation' => 'utf8_unicode_ci',
'prefix' => '',
], $this->connectionName);
....
....
$pimple['db'] = function ($c) use ($capsule) {
return $capsule;
};
I call that in my dependencies.php
Then when I come to routes I do this:
$container = $app->getContainer();
$validatorMiddleware = new \....\Middleware\BaseMiddleware($container->get('db'));
I changed my middleware init to this
private function initiateValidatorFactory($dbConnectionSettings)
{
$validatorFactory = new ValidatorFactory(
new Translator(new FileLoader(new Filesystem(), "en"), "en"),
null);
$resolver = new ConnectionResolver(['mysql' => $dbConnectionSettings->getConnection('mysql')]);
$verifier = new DatabasePresenceVerifier($resolver);
$validatorFactory->setPresenceVerifier($verifier);
$this->validatorFactory = $validatorFactory;
}
Notice how my variables don't make sense any more but you will figure it out how to make it nicer and stuff. (me included). Most important thing is this works somehow. I know it is hacky. If you wish to post an answer that does not include hacks please do =).

Related

How to use Symfony Messenger component in standalone code to send AMQP messages

We're using Symfony Messenger in a Symfony 5 project to integrate with RabbitMQ. It works fine when sending messages within Symfony, but I need the ability to use the Messenger component to send messages from some legacy PHP applications that are not built with the Symfony framework.
Under Symfony, it handles all the magic by injecting the MessageBusInterface and all I need to do is something like this:
public function processTestMessage(MessageBusInterface $bus)
{
$bus->dispatch(new TestMessage('Hello World!');
}
I need to somehow instantiate my own version of $bus that will send AMQP messages the same way that Symfony does. I've been trying to recreate everything that Symfony does behind the scenes to accomplish this, but have not been able to put all the details together.
The crux of the problem is to create my own SendMessageMiddleware that does the same thing as Symfony. After that, it's simple:
$sendersLocator = ???
$eventDispatcher = ???
$sendMessageMiddleware = new($sendersLocator, $eventDispatcher);
$bus = new MessageBus([$sendMessageMiddleware]);
Does anyone have any examples of working code that uses the Messenger component to send AMQP messages outside of Symfony?
This can be improved but it works for me:
use Symfony\Component\Messenger\Bridge\Amqp\Transport\AmqpSender;
use Symfony\Component\Messenger\Bridge\Amqp\Transport\Connection;
use Symfony\Component\Messenger\Envelope;
use Symfony\Component\Messenger\MessageBus;
use Symfony\Component\Messenger\Middleware\SendMessageMiddleware;
use Symfony\Component\Messenger\Transport\Sender\SendersLocatorInterface;
$sendersLocator = new class implements SendersLocatorInterface {
public function getSenders(Envelope $envelope): iterable
{
$connection = new Connection(
[
'hosts' => 'localhost',
'port' => 5672,
'vhosts' => '/',
'login' => 'guest',
'password' => 'guest'
],
[
'name' => 'messages'
],
[
'messages' => []
]
);
return [
'async' => new AmqpSender($connection)
];
}
};
$middleware = new SendMessageMiddleware($sendersLocator);
$bus = new MessageBus([$middleware]);
$bus->dispatch(new MyMessage());
I modified the above answer to let me pass the RabbitMQ credentials as an environment variable. This is what I needed for my application. I was trying to write my own DSN parser and discovered that Symfony already does it, so I basically lifted the code from there.
If the environment variable is not set, it defaults to use the same settings shown in the example above.
use Symfony\Component\Messenger\Bridge\Amqp\Transport\AmqpSender;
use Symfony\Component\Messenger\Bridge\Amqp\Transport\Connection;
use Symfony\Component\Messenger\Envelope;
use Symfony\Component\Messenger\MessageBus;
use Symfony\Component\Messenger\Middleware\SendMessageMiddleware;
use Symfony\Component\Messenger\Transport\Sender\SendersLocatorInterface;
$sendersLocator = new class implements SendersLocatorInterface {
public function getSenders(Envelope $envelope): iterable
{
$dsn = getenv('MESSENGER_TRANSPORT_DSN') ?: $_ENV['MESSENGER_TRANSPORT_DSN'];
$connection = Connection::fromDsn($dsn);
return [
'async' => new AmqpSender($connection)
];
}
};
$middleware = new SendMessageMiddleware($sendersLocator);
$bus = new MessageBus([$middleware]);
$bus->dispatch(new MyMessage());

Silex with Doctrine and PHP classes

So, I'm trying to get around in Silex. Just learn the way it works and I'm trying to use Doctrine in it. I can use it on the index.php, but I'd also like to use it in my classes. These lines are used in the normal root file (index.php):
$images = $app['db']->prepare("SELECT * FROM images");
$images->execute();
$images = $images->fetchAll(\PDO::FETCH_CLASS, \AI\Models\Image::class);
So that would give me the ability to do something with the images. But I don't want to work this way. I'd like classes to do it all for me, so that I just script some methods which do all the hard work for me. That would let me just run one line for each Route in index.php
The problem is that I don't know how to connect with Doctrine from inside my classes. Because there is no '$app' in there. I think it would be weird to start the app inside of a class.
So let's say I wanted to create a user class. This SQL would give me all the users: "SELECT * FROM users". But how would I use Doctrine inside the User class?
<?php
namespace Models;
class User {
public function find($user){
if($user) {
$field = (is_numeric($user)) ? 'id' : 'username';
$sql = "SELECT * FROM users";
$data = // RUN QUERY $SQL
if($data->count()) {
$this->_data = $data->all();
return true;
}
}
return false;
}
}
In your index.php follow these steps.
Create instance of the silex application:
$app = new Silex\Application();
$app->register(new Silex\Provider\ServiceControllerServiceProvider());
Set the database configuration:
$config = new \Doctrine\DBAL\Configuration();
$connParams = array(
'driver' => 'driver',
'dbname' => 'dbname',
'host' => 'host',
'user' => 'user',
'password' => 'pass',
'charset' => 'charset',
'port' => 'port'
);
Connect to database:
$conn = \Doctrine\DBAL\DriverManager::getConnection($connParams, $config);
Now you have different ways to make this db instance accessible throughout your app. You can whether make a global variable adding the instance in it:
global $dbcon;
$dbcon = $conn;
Or simply add it to the $app itself:
$app['dbcon'] = $conn;
Furthermore you might want to add a constructor to your models like this:
public function __construct($db)
{
$this->db = $db;
}
You would need to inject those instances in your controller.
I looked through the docs real quick and think I found what you need.
Here is a link to the documentation page : http://silex.sensiolabs.org/doc/2.0/providers/service_controller.html.
the documentation page explains everything you need to know to get what you want to achieve.

ZF1: unit testing of authentication functionality

I am new to unit-testing and trying to implement first set of tests for Index controller in Zend Framework 1 application.
In this controller I have a login action that uses Zend_Auth for checking provided user's credentials. I don't quite understand what is the best way to test it:
Create separate test database config. Before making any tests upload SQL file with initial state of the database and set this test database as a default database.
Redefine (somehow) Zend_Auth so that it always return predefined array with user information (or empty array) and test this scenario. I found this implementation in Zend Framework 2, but no for version 1.
I would appreciate any advice and links to projects in ZF1 that have unit testing for authentication and functionality connected with database in general.
UPD
Here is a login action of Index Controller that I'm going to test
public function loginAction()
{
$loginForm = new Form_Login();
$modelUser = new Model_User();
$formData = $this->getRequest()->getPost();
$flashMessenger = $this->_helper->getHelper('FlashMessenger');
if(!empty($formData)){
if($loginForm->isValid($formData)){
$authAdapter = new Zend_Auth_Adapter_DbTable(Zend_Db_Table::getDefaultAdapter());
$authAdapter->setTableName('user')
->setIdentityColumn('email')
->setCredentialColumn('password')
->setCredentialTreatment('MD5(?)');
$authAdapter->setIdentity($formData['form_email']);
$authAdapter->setCredential($formData['form_password']);
$auth = Zend_Auth::getInstance();
$result = $auth->authenticate($authAdapter);
if($result->isValid()) {
$userData = $authAdapter->getResultRowObject();
$modelUser->setTimestamp($userData->user_id);
$this->_processLoggedInUser($userData);
} else {
$loginForm->addError("Incorrect email/password");
}
}
}
//Retrieve Facebook App ID
$this->view->facebookAppId = Zend_Registry::get('facebookAppId');
$this->view->googleClientId = Zend_Registry::get('googleClientId');
$this->view->loginForm = $loginForm;
$this->view->userMsg = $flashMessenger->getMessages();
}
So, I thought, maybe I can use Zend_Test_DbAdapter, set it as a default adapter and make it to return predefined set of data?
I've found out 2 ways to work with db data during unit tests:
1.
public function testStudentLogin()
{
$config = new Zend_Config_Ini(APPLICATION_PATH."/configs/application.ini", APPLICATION_ENV);
$testDatabaseConfig = $config->testDb;
$connection = Zend_Db::factory($testDatabaseConfig);
Zend_Db_Table::setDefaultAdapter($adapter);
$this->request->setMethod('POST');
$this->request->setPost(array('form_email' => 'student', 'form_password' => '123'));
$this->dispatch('/index/login');
$this->assertController('index');
$this->assertAction('login');
$this->assertRedirect('/index/student-professor');
}
So, here you store test db credentials in application.ini. Then you initialise connection to it through adapter and change Zend_Db_Table::setDefaultAdapter.
2.
public function testStudentLogin()
{
$adapter = new Zend_Test_DbAdapter();
$stmt1Rows = array(array('user_id' => 1, 'email' => 'student', 'password' => '202cb962ac59075b964b07152d234b70', 'user_type' => 'consumer', 'zend_auth_credential_match' => 1));
$stmt1 = Zend_Test_DbStatement::createSelectStatement($stmt1Rows);
$adapter->appendStatementToStack($stmt1);
$this->request->setMethod('POST');
$this->request->setPost(array('form_email' => 'student', 'form_password' => '123'));
$this->dispatch('/index/login');
$this->assertController('index');
$this->assertAction('login');
$this->assertRedirect('/index/student-professor');
}
Here you use Zend_Test_DbAdapter where you can predefine what data will be returned. I think that using separate database for test purpose makes your code cleaner, so I'll probably use this approach. If you have other ideas/best practices let me know

Add Doctrine DBAL into own php project

Trying to add Doctrine DBAL into my own project to use it to access my db etc. I don't have composer and i never used it. This is what i am trying to do according to the docu:
use Doctrine\Common\ClassLoader;
class Connection
{
var $connection;
//Constructor
public function __construct()
{
require_once "doctrine/Common/ClassLoader.php";
$classLoader = new ClassLoader('Doctrine', 'doctrine');
$classLoader->register();
$config = new Configuration();
$connectionParams = array(
'dbname' => 'mydb',
'user' => 'root',
'password' => "",
'host' => 'localhost',
'driver' => 'pdo_mysql',
);
$this->connection = \Doctrine\DBAL\DriverManager::getConnection($connectionParams, $config);
}
}
This is taken from here:
-http://docs.doctrine-project.org/projects/doctrine-dbal/en/latest/reference/configuration.html
and:
- http://docs.doctrine-project.org/projects/doctrine-dbal/en/latest/reference/introduction.html
I have the Common and DBAL folder added into my project
My folder structure looks like this:
root
doctrine
DBAL
Common
php stuff
index.php (where connection.php) is executed
So what happens is that i either get "Cannot find class XY" or something similar, based upon what i change on the code. I never am able to execute it as it should following the tutorial.
What am i doing wrong here?
I just want to have the connection object, where i can start doing my stuff like useing the query builder etc...
I am completely lost here...
UPDATE: Installed composer as requested and have this Code now:
use Doctrine\DBAL\Configuration;
class Connection
{
var $connection;
//Constructor
public function __construct()
{
$config = new Configuration();
$connectionParams = array(
'url' => 'mysql://root:secret#localhost/mydb',
);
$this->connection = \Doctrine\DBAL\DriverManager::getConnection($connectionParams, $config);
}
Which is the 2nd code example in my 1st link. Tells me " Class 'Doctrine\DBAL\Configuration' not found ". Funny thing is, that IntelliJ can perfectly autocomplete the path (suggests me Configuration when finishing DBAL in the path) but PHP doesn't find it. If i remove the new Configuration PHP just tells me, that it doesn't find the DriverManager...
I installed it correctly via composer though, at least composer tells me it is installed correctly now (Where does composer save the libs?)
You now need to require composers autoload file.
require __DIR__.'/vendor/autoload.php';
use Doctrine\DBAL\Configuration;
class Connection
{
var $connection;
//Constructor
public function __construct()
{
$config = new Configuration();
$connectionParams = array(
'url' => 'mysql://root:secret#localhost/mydb',
);
$this->connection = \Doctrine\DBAL\DriverManager::getConnection($connectionParams, $config);
}
Please note, depending on your directory structure, the autoload file might be somewhere else, but usually this should work.
Pay attention to the use of namespaces: if the Doctrine namespace for its loader is Doctrine\Common\ClassLoader, you have to put the files inside the Doctrine\Common folder ("Doctrine" with a capital "D").
See the code snippet shown inside the Introduction chapter of the Doctrine DBAL documentations.

CakePHP Issue: Unexpected call to database

A question for the CakePHP community:
I am attempting to upgrade a website built using CakePHP 1.3.11 to CakePHP 2.0.4. It is a very simple site with no database attached, I wish to use the PagesController / PageModel to validate the data passed to it from a Form and then send an E-Mail based on the information supplied.
The $useTable variable in PageModel has been set to false and the database.php $default is left as.. well, default (the reasoning being i dont need a database conneciton at anytime).
The problem comes in, when I try loading the view, i get:
Error: SQLSTATE[28000] [1045] Access denied for user 'user'#'localhost' (using password: YES) requires a database connection.
Why would it give me this when at no time do i want a call to any database? Worked fine in 1.3.11, am I missing something...? Hope I explained the dilemma adequately. Any input would be much appreciated.
It's slightly different for Cake 2.0 I believe; I've used this on a similar project:
In:
APP/Model/Datasource/Database/fake.php // fake.php is your class name
<?php
App::uses('DboSource', 'Model/Datasource');
// allows Cake to function without a database connection
class Fake extends DboSource {
public $description = "Disable the requirement of connecting to a database.";
function connect()
{
$this->connected = true;
return $this->connected;
}
function disconnect() // probably not necessary but for completion
{
$this->connected = false;
return !$this->connected;
}
}
and in database.php
class DATABASE_CONFIG {
public $default = array(
'datasource' => 'Database/Fake', // usually Database/Mysql
'persistent' => false,
'host' => 'localhost',
'login' => 'user',
'password' => '',
'database' => '',
'prefix' => '',
'encoding' => 'utf8',
);
// I left the other keys in in case you need to swap
// to a real connection quickly at some point.
this works in 2.0.4
It seems that you need to create a dummy datasource if you are not using any database.
I have never done this, but this thread looks promising: http://groups.google.com/group/cake-php/browse_thread/thread/1254d64d4b21b24c

Categories