zend2 mysql - joining table using TableGateway - zend-framework2

I want to aquire data from two mySql tables:
SELECT L.id AS 'l_id', L.date, L.action, U.id AS 'u_id', U.name, U.surname
FROM cases_log L, users U
WHERE L.user = U.id
LIMIT 0,30
So, I've decided to use $select->join, but it doesn't work in way I want. It has aqured data only from cases_log table.
SELECT *
FROM `cases_log`
JOIN users
ON users.id = cases_log.user
Module.php:
'HistoryTable' => function($sm)
{
$tableGateway = $sm->get('HistoryTableGateway');
$table = new HistoryTable($tableGateway);
return $table;
},
'HistoryTableGateway' => function ($sm)
{
$dbAdapter = $sm->get('Zend\Db\Adapter\Adapter');
$resultSetPrototype = new ResultSet();
$resultSetPrototype->setArrayObjectPrototype(new History());
return new TableGateway('cases_log', $dbAdapter, null, $resultSetPrototype);
},
HistoryTable.php:
$table = $this->tableGateway;
$select = $table->getSql()->select();
//$select->from(array('L' => 'cases_log'))->join(array('U' => 'users'),'L.user = U.id');
$select->join('users', 'users.id = cases_log.user');
$select->limit(10);
$select->offset(0);
$resultSet = $table->selectWith($select);
return $resultSet;
As You can see, in commented line, I've tried to do something in $select->from - but without result, because $select->from is read only ...
I'm new to ZF2 so, I miss somethis maybe?

$table = $this->tableGateway;
$select = $table->getSql()->select();
$select->columns(['l_id' => 'id', 'date', 'action']);
$select->join('users', 'users.id = cases_log.user', ['u_id' => 'id', 'name', 'surname']);
$select->limit(10);
$select->offset(0);
produces the correct sql (except the aliases for the table)

Related

Show username of logged in user in zf2

I have login and logout system in ZF2. I want to show username of logged in user when he/she is logged in. Screen shot is given below:
I have different views like view/provinces/index.phtml, view/districts/index.phtml, etc.
I have layout.phtml in view/layout/layout.phtml, in which I described layout for admin which is for every view. So It is necessary to access username of logged in user in layout.phtml.
I have also corresponding controllers like Controller/ProvincesController.php, Controller/DistrictsController.php etc. I can access username of logged in user in Controller/ProvincesController.php etc by the code:
public function getAuthService()
{
$this->authservice = $this->getServiceLocator()->get('AuthService');
return $this->authservice;
}
$username = $this->getAuthService()->getStorage()->read();
But I am unable to access value of username of logged in user in layout.phtml.
So if anyone know about it or have simple idea or practice about it, then let me know please.
Module.php:
<?php
namespace Admin;
use Admin\Model\Profile;
use Admin\Model\ProfileTable;
use Admin\Model\Provinces;
use Admin\Model\ProvincesTable;
use Admin\Model\Districts;
use Admin\Model\DistrictsTable;
use Admin\Model\User;
use Admin\Model\UserTable;
use Zend\Db\ResultSet\ResultSet;
use Zend\Db\TableGateway\TableGateway;
use Zend\Mvc\ModuleRouteListener;
use Zend\Mvc\MvcEvent;
use Zend\ModuleManager\Feature\AutoloaderProviderInterface;
use Zend\Authentication\Adapter\DbTable as DbTableAuthAdapter;
use Zend\Authentication\AuthenticationService;
class Module implements AutoloaderProviderInterface
//class Module
{
public function getConfig()
{
return include __DIR__ . '/config/module.config.php';
}
public function getServiceConfig()
{
return array(
'abstract_factories' => array(),
'aliases' => array(),
'factories' => array(
// SERVICES
'AuthService' => function($sm) {
$dbAdapter = $sm->get('Zend\Db\Adapter\Adapter');
$dbTableAuthAdapter = new DbTableAuthAdapter($dbAdapter, 'user','username','password', 'MD5(?)');
$authService = new AuthenticationService();
$authService->setAdapter($dbTableAuthAdapter);
return $authService;
},
// DB
'UserTable' => function($sm) {
$tableGateway = $sm->get('UserTableGateway');
$table = new UserTable($tableGateway);
return $table;
},
'UserTableGateway' => function ($sm) {
$dbAdapter = $sm->get('Zend\Db\Adapter\Adapter');
$resultSetPrototype = new ResultSet();
$resultSetPrototype->setArrayObjectPrototype(new User());
return new TableGateway('user', $dbAdapter, null,
$resultSetPrototype);
},
// FORMS
'LoginForm' => function ($sm) {
$form = new \Admin\Form\LoginForm();
$form->setInputFilter($sm->get('LoginFilter'));
return $form;
},
// FILTERS
'LoginFilter' => function ($sm) {
return new \Admin\Form\LoginFilter();
},
'Admin\Model\ProvincesTable' => function($sm) {
$tableGateway = $sm->get('ProvincesTableGateway');
$table = new ProvincesTable($tableGateway);
return $table;
},
'ProvincesTableGateway' => function ($sm) {
$dbAdapter = $sm->get('Zend\Db\Adapter\Adapter');
$resultSetPrototype = new ResultSet();
$resultSetPrototype->setArrayObjectPrototype(new Provinces());
return new TableGateway('provinces', $dbAdapter, null, $resultSetPrototype);
},
'Admin\Model\DistrictsTable' => function($sm) {
$tableGateway = $sm->get('DistrictsTableGateway');
$table = new DistrictsTable($tableGateway);
return $table;
},
'DistrictsTableGateway' => function ($sm) {
$dbAdapter = $sm->get('Zend\Db\Adapter\Adapter');
$resultSetPrototype = new ResultSet();
$resultSetPrototype->setArrayObjectPrototype(new Districts());
return new TableGateway('districts', $dbAdapter, null, $resultSetPrototype);
},
),
'invokables' => array(),
'services' => array(),
'shared' => array(),
);
}
public function getAutoloaderConfig()
{
return array(
'Zend\Loader\StandardAutoloader' => array(
'namespaces' => array(
// if we're in a namespace deeper than one level we need to fix the \ in the path
__NAMESPACE__ => __DIR__ . '/src/' . str_replace('\\', '/' , __NAMESPACE__),
),
),
);
}
}
Thanks in advance.
The recommend way would be to use identity (https://framework.zend.com/manual/2.4/en/modules/zend.view.helpers.identity.html) view helper. Then in any view model you could use it as follow:
if ($user = $this->identity()) {
echo 'Logged in as ' . $this->escapeHtml($user->getUsername());
} else {
echo 'Not logged in';
}
In order to make it work you have to register your authentication service under specific name- Zend\Authentication\AuthenticationService.
So in your module.config.php file, add to service_manager:
'service_manager' => array(
'aliases' => array(
'Zend\Authentication\AuthenticationService' => 'AuthService', // <--- this line
),
'invokables' => array(
'AuthService' => 'Your\Authentication\Class',
),
),
Then you should be able to use identity controller plugin and view helper.
In your case, Module.php should look like this:
...
public function getServiceConfig()
{
return array(
'abstract_factories' => array(),
'aliases' => array(
'Zend\Authentication\AuthenticationService' => 'AuthService', // <--- this line
),
'factories' => array(
// SERVICES
'AuthService' => function($sm) {
$dbAdapter = $sm->get('Zend\Db\Adapter\Adapter');
$dbTableAuthAdapter = new DbTableAuthAdapter($dbAdapter, 'user','username','password', 'MD5(?)');
$authService = new AuthenticationService();
$authService->setAdapter($dbTableAuthAdapter);
return $authService;
},
// DB
'UserTable' => function($sm) {
$tableGateway = $sm->get('UserTableGateway');
$table = new UserTable($tableGateway);
return $table;
},
'UserTableGateway' => function ($sm) {
$dbAdapter = $sm->get('Zend\Db\Adapter\Adapter');
$resultSetPrototype = new ResultSet();
$resultSetPrototype->setArrayObjectPrototype(new User());
return new TableGateway('user', $dbAdapter, null,
$resultSetPrototype);
},
// FORMS
'LoginForm' => function ($sm) {
$form = new \Admin\Form\LoginForm();
$form->setInputFilter($sm->get('LoginFilter'));
return $form;
},
// FILTERS
'LoginFilter' => function ($sm) {
return new \Admin\Form\LoginFilter();
},
'Admin\Model\ProvincesTable' => function($sm) {
$tableGateway = $sm->get('ProvincesTableGateway');
$table = new ProvincesTable($tableGateway);
return $table;
},
'ProvincesTableGateway' => function ($sm) {
$dbAdapter = $sm->get('Zend\Db\Adapter\Adapter');
$resultSetPrototype = new ResultSet();
$resultSetPrototype->setArrayObjectPrototype(new Provinces());
return new TableGateway('provinces', $dbAdapter, null, $resultSetPrototype);
},
'Admin\Model\DistrictsTable' => function($sm) {
$tableGateway = $sm->get('DistrictsTableGateway');
$table = new DistrictsTable($tableGateway);
return $table;
},
'DistrictsTableGateway' => function ($sm) {
$dbAdapter = $sm->get('Zend\Db\Adapter\Adapter');
$resultSetPrototype = new ResultSet();
$resultSetPrototype->setArrayObjectPrototype(new Districts());
return new TableGateway('districts', $dbAdapter, null, $resultSetPrototype);
},
),
'invokables' => array(),
'services' => array(),
'shared' => array(),
);
}
...
Then in your layout or any other .phtml file:
layout.phtml
...
<?php if ($this->identity()): ?>
<p>Welcome, <?php echo $this->identity()->getUsername(); ?></p>
<?php endif; ?>
Taking help of Mr. SzymonM's answer, I changed my Module.php as suggested by him, and write the following simple code in layout.phtml
This solve my issue and username is shown with first letter in Upper case.
<?php
if ($this->identity())
{
echo ucfirst($this->identity());
}
?>
//ucfirst is php function which make first letter Uppercase.

Symfony form builder default select by EntityType

I try to create form with html select element using EntityType. I must get values by some condition and by this condition necessary default value not select from database. So i get all options values, without one, that must be a default value. So i try to find a way to put this value to select. What i tried...
Set value in form:
$growing = $em->getRepository('FarmBundle:Growing')->findGrowing($user_id);
$garden = $em->getRepository('FarmBundle:Garden')->find(7);
$tableForm = $this->createForm('FarmBundle\Form\GrowingType', $growing, ['user_id' => $user_id]);
$tableForm->get('garden')->setData($garden);
$form = $tableForm->createView()
Then i tried to set data in entity:
$growing = $em->getRepository('FarmBundle:Growing')->findGrowing($user_id);
$garden = $em->getRepository('FarmBundle:Garden')->find(7);
$growing->setGarden($garden);
$tableForm = $this->createForm('FarmBundle\Form\GrowingType', $growing, ['user_id' => $user_id]);
$form = $tableForm->createView()
Then i tried to set default select value in form_builder using 'data' attribute:
$growing = $em->getRepository('FarmBundle:Growing')->findGrowing($user_id);
$garden = $em->getRepository('FarmBundle:Garden')->find(7);
$tableForm = $this->createForm('FarmBundle\Form\GrowingType', $grow, [
'user_id' => $user_id,
'selected_choice' => $garden
]);
$form = $tableForm->createView();
Form_builder code:
class GrowingType extends AbstractType
{
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder
->add('id', HiddenType::class)
->add('garden', EntityType::class , [
'class' => 'FarmBundle\Entity\Garden',
'query_builder' => function (GardenRepository $gr) use ($options) {
return $gr->queryFreeGardens($options['user_id']);
},
'attr' => [
'data-type' => 'text',
'class' => 'table-select',
'disabled' => true
],
'required' => false,
'data' => $options['selected_choice']
]);
}
/**
* #param OptionsResolver $resolver
*/
public function configureOptions(OptionsResolver $resolver)
{
$resolver->setDefaults(array(
'data_class' => 'FarmBundle\Entity\Growing',
'selected_choice' => null,
'user_id' => null
));
}
}
And code of query for query builder:
class GardenRepository extends \Doctrine\ORM\EntityRepository
{
public function queryFreeGardens($user_id)
{
$qb = $this->createQueryBuilder('g')
->leftJoin('g.growing', 'grow')
->where('grow.plantDate is NULL')
->orWhere('grow.endDate is not NULL')
->andWhere('g.user = :user_id')
->orderBy('g.name')
->setParameter('user_id', $user_id);
return $qb;
}
}
And all of this 3 methods not works. Result is one, if entity not get for query in query builder, i cant set this entity. If i will set entity as default value, that was in query builder all will works fine.
How can i solve this problem?
try this
in controller:
$growing = $em->getRepository('FarmBundle:Growing')->findGrowing($user_id);
$garden = $em->getRepository('FarmBundle:Garden')->find(7);
$tableForm = $this->createForm('FarmBundle\Form\GrowingType', $grow, [
'user_id' => $user_id,
'additional_id' => 7
]);
$form = $tableForm->createView();
in form:
class GrowingType extends AbstractType
{
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder
->add('id', HiddenType::class)
->add('garden', EntityType::class , [
'class' => 'FarmBundle\Entity\Garden',
'query_builder' => function (GardenRepository $gr) use ($options) {
return $gr->queryFreeGardens($options['user_id'], $options['additional_id');
},
'attr' => [
'data-type' => 'text',
'class' => 'table-select',
'disabled' => true
],
'required' => false
]);
}
/**
* #param OptionsResolver $resolver
*/
public function configureOptions(OptionsResolver $resolver)
{
$resolver->setDefaults(array(
'data_class' => 'FarmBundle\Entity\Growing',
'additional_id' => null,
'user_id' => null
));
}
}
in repository:
class GardenRepository extends \Doctrine\ORM\EntityRepository
{
public function queryFreeGardens($user_id, $additional_id)
{
$qb = $this->createQueryBuilder('g')
->leftJoin('g.growing', 'grow')
->where('grow.plantDate is NULL')
->andWhere('g.id = :additional_id')
->orWhere('grow.endDate is not NULL')
->andWhere('g.user = :user_id')
->andWhere('g.id = :additional_id')
->orderBy('g.name')
->setParameter('user_id', $user_id)->setParameter('additional_id', $additional_id);
return $qb;
}
}
maybe you will need to adjust your repository method to retrieve values in right way. There are or clause, you should add this additional id to both branches of your or clause. The main idea is to retrieve you selected object too.

Yii2 best Implementation when you want to consume MS SQL stored procedure

I need advice on the best way to use yii2 with stored procedures. As this area is very grey.
I currently have a Yii 1 project implementation and like any developer, we are always looking out for new ways to speed up and write better code than we did the previous day.
I want to start off and port my new app to yii2 and was wondering what is the best way to consume stored procedure as that is the architecture currently in the organization and as much as I would with to interact with the database directly using Yii Active records it just impossible.
So in my current Yii 1 project I have created a class in component and imported it in config/main.php
'import' => array(
'application.models.*',
'application.components.SqlResource.*',
),
Then i proceeded to construct my class as
class SqlResource extends CApplicationComponent {
const LOG_CAT = "ext.SqlResource";
public $resources = array();
public $db;
public $mssql;
/**
* __construct
*
* #access public
* #return void
*/
public function __construct() {
$serverUrl = Yii::app()->params->mssql['host'];
$serverUser = Yii::app()->params->mssql['user'];
$serverPass = Yii::app()->params->mssql['password'];
$serverDb = Yii::app()->params->mssql['db_name'];
try {
$this->mssql = new PDO('dblib:host=' . $serverUrl . ';dbname=' . $serverDb, $serverUser, $serverPass);
$this->mssql->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
} catch (PDOException $e) {
Yii::log("Connection Error: #(DB connection was unavailable )[" . $e->getMessage() . "] ", "error", self::LOG_CAT);
die($e->getMessage());
}
}
/**
*
* #param type $data array containg username and password from the login form
* #return array
*/
public function ExampleSqlResourceFunction($username, $password) {
if (!empty($username) && is_string($username)) {
$procedure = "exec login_access #username = :username, #password = :password"; //Procedure to be called
$query = $this->mssql->prepare($procedure); //PDO prepare a query for execution using bind parameters to avaid leve 1 and level 2 sql injection
$start = array_sum(explode(' ', round(microtime(TRUE) * 1000))); //start time to calculate the time it takes to execute a query. the log time is logged for debugging process
$query->bindValue(":username", $username, PDO::PARAM_STR); //bind the alias username from the prepared statment to the actual value and specify the datatype for this variable
$query->bindValue(":password", $password, PDO::PARAM_STR); //bind the alias password from the prepared statment to the actual value and specify the datatype for this variable
$execute = $query->execute(); //execute the query
$stop = array_sum(explode(' ', round(microtime(true) * 1000))); //stop time to calculate the time it takes to execute a query. the log time is logged for debugging process
$totalMs = substr(($stop - $start), 0, 5); //total ms it took to execute the query
$array = array(); //declare the return $array as an array
if ($execute == TRUE) {//If query executes successfully return $return array $results
$key_column = null; //format the retun array
while ($obj = $query->fetch(PDO::FETCH_ASSOC)) {
isset($obj[$key_column]) ? $array[$obj[$key_column]] = $obj : $array[] = $obj;
}//log the how long it took to execute the query and the trace which procedure was executed
Yii::log("Took $totalMs ms to fetch Login Details result set", "info", self::LOG_CAT);
Yii::log("[login] " . '" ' . $procedure . '"', "trace", self::LOG_CAT);
return $array;
} else {
$results = 'not execute';
return $results;
}
}
}
After that i initialize my SqlResouce in my controller as follows
public function actionExampleControllerAction() {
$sql = new SqlResource();
$results = $sql->ExampleSqlResourceFunction();
if (isset($results) && !empty($results)) {
foreach ($results as $key => $value) {
$array[$key] = array(
'type' => 'column',
'name' => $value["Department_Name"],
'value' => $value['Count'],
);
}
}
echo json_encode($array, JSON_NUMERIC_CHECK);
Yii::app()->end();
}
Use createCommand function inside Yii2 app.
$result = \Yii::$app->db->createCommand("exec login_access #username = :username, #password = :password")
->bindValue(':username' , $username)
->bindValue(':password', $password)
->execute();
To change db to another just create another component like dbMS
//Your MySql db
'db'=>
[
'class' => 'yii\db\Connection',
'dsn' => 'mysql:host=localhost;dbname=my_database',
'username' => 'root',
'password' => '',
'charset' => 'utf8',
],
//Your MS SQL db
'dbMS'=>
[
'class' => 'yii\db\Connection',
'dsn' => 'dblib:host=mssqlserver;dbname=my_database',
'username' => 'sa',
'password' => 'superpass',
'charset' => 'utf8',
],
So now you can easily and dynamically change your MySQL db to MSSQL dbMS on runtime.
$result = \Yii::$app->dbMS->createCommand("exec login_access #username = :username, #password = :password")
->bindValue(':username' , $username)
->bindValue(':password', $password)
->execute();

How to validate input array with a same name in laravel controller

I have a problem when a i try to insert record into table like this .
$data = array();
foreach($input['user_id'] as $key => $user_id) {
$data[$key]['user_id'] = $user_id;
}
foreach($input['start_on'] as $key => $start_on) {
$data[$key]['start_on'] = $start_on;
}
$this->validate($request, [
'time_start' => 'required|date',
'time_end' => 'required|date|after:time_start',
]);
$rules = [
'start_on' => 'required|date|after:time_start|before:time_end|different:start_on'
];
// Iterate and validate each question
foreach ($data as $value)
{
$validator = Validator::make( $value, $rules );
// if ($validator->fails()) return $validator->messages()->all();
}
I want to check start_on not equals another start_on.So what can i do?

zf2 The supplied parameters to DbTable failed to produce a valid sql statement, please check table and column names for validity

On authentication I am getting an error message
"The supplied parameters to DbTable failed to produce a valid sql statement, please check table and column names for validity."
my login controller code is
$form= new login();
$request=$this->getRequest();
if ($request->isPost())
{
$formValidator = new rotaryfilter();
$post=$request->getPost();
$form->setInputFilter($formValidator->getInputFilter());
$form->setData($request->getPost());
if($form->isValid())
{
$formValidator->exchangeArray($form->getData());
$dbAdapter = $this->serviceLocator->get('Zend\Db\Adapter\Adapter');
$authAdapter = new DbTable($dbAdapter,'Login','username','pwd');
$authAdapter->setIdentity($formValidator->username)
->setCredential($formValidator->pwd);
//->setCredentialTreatment('MD5(?)');
$authService = $this->serviceLocator->get('auth_service');
$authService->setAdapter($authAdapter);
$result = $authService->authenticate();
if($result->isValid())
{
echo 'valid';
exit();
}
else { echo 'invalid';exit();}
}
}
return array('form'=> $form);
and my module.php contains
public function getServiceConfig()
{
return array(
'factories' => array(
'auth_service' => function ($sm) {
$authService = new AuthenticationService(new SessionStorage('auth'));
return $authService;
},
'General\Model\Login' => function($sm) {
$tableGateway = $sm->get('LoginGateway');
$table = new Login($tableGateway);
return $table;
},
'LoginGateway' => function ($sm) {
$dbAdapter = $sm->get('Zend\Db\Adapter\Adapter');
$resultSetPrototype = new ResultSet();
$resultSetPrototype->setArrayObjectPrototype(new rotaryfilter());
return new TableGateway('Login', $dbAdapter, null, $resultSetPrototype);
},
),);
}
This may seems old but I was able to solve this error. This error is caused from you MySQL version.
This one works for me. All you need to do is to remove the driver_options from your db setup, this code is usually located at your global.php or .local.php from your Config file.
Change FROM:
'db' => array(
'driver' => 'Pdo_Mysql',
'dsn' => 'mysql:dbname=dbName;host=localhost',
'username' => 'dbUser',
'password' => 'dbPass',
'driver_options' => array(
PDO::MYSQL_ATTR_INIT_COMMAND => 'SET NAMES \'UTF8\''
),
),
TO
'db' => array(
'driver' => 'Pdo_Mysql',
'dsn' => 'mysql:dbname=dbName;host=localhost',
'username' => 'dbUser',
'password' => 'dbPass',
),
Thank you. This solution solved my problem.

Resources