Phalcon\Session\Bag.. how to use them? - php

In my project i use following code to access session variables via Session Bags in services:
public function __construct()
{
// Create session bag
$className = get_class($this);
$this->storage = new Phalcon\Session\Bag($className);
}
But this gives an exception "A dependency injection object is required to access the 'session' service".
Ok, it seems that we need to setup a DI here. Most simple way - to define not shared sessionBag service in DI ($di will be set automatically then). But how can i understand which name i should setup for Session bag this way? Example:
$di->set('sessionBag', function() use ($config) {
$name = ''; // ???
$bag = new \Phalcon\Session\Bag($name);
return $bag;
});

You can make your class inherit from Phalcon\DI\Injectable, a session bag is implicitly created when you access the persistent property:
class MyComponent extends Phalcon\DI\Injectable
{
public function someMethod()
{
$this->persistent->someName = "peter";
}
}

//Start the session the first time when some component request
// the session service
$di->setShared('session', function() {
$session = new Phalcon\Session\Adapter\Files();
$session->start();
return $session;
});
Example:
auth.php:
public function __construct(){
$this->_di = \Phalcon\DI::getDefault ();
$this->user = new \Phalcon\Session\Bag(get_class());
$this->user->setDI($this->_di);
}
/**
*
* #param int
*
* #return bool
*/
public function authenticate($identity){
$this->user->identity=$identity;
}
/**
* #return boolean
*/
public function isAuthenticate(){
return $this->user->identity?true:false;
}

Related

How do I fetch the PHP DI container?

How do I load a database container using PHP DI?
This is one of the variations I have tried up until now.
Settings.php
<?php
use MyApp\Core\Database;
use MyApp\Models\SystemUser;
return [
'Database' => new Database(),
'SystemUser' => new SystemUser()
];
init.php
$containerBuilder = new \DI\ContainerBuilder();
$containerBuilder->addDefinitions('Settings.php');
$container = $containerBuilder->build();
SystemUserDetails.php
<?php
namespace MyApp\Models\SystemUser;
use MyApp\Core\Database;
use MyApp\Core\Config;
use MyApp\Helpers\Session;
/**
*
* System User Details Class
*
*/
class SystemUserDetails
{
/*=================================
= Variables =
=================================*/
private $db;
/*===============================
= Methods =
================================*/
/**
*
* Construct
*
*/
public function __construct(Database $db)
{
# Get database instance
// $this->db = Database::getInstance();
$this->db = $db;
}
/**
Too few arguments to function MyApp\Models\SystemUser\SystemUserDetails::__construct(), 0 passed in /www/myapp/models/SystemUser.php on line 54 and exactly 1 expected
File: /www/myapp/models/SystemUser/SystemUserDetails.php
Shouldn't the database get loaded automatically?
Trace:
Currrently, My main index.php file extends init.php which is the file where it create the container (pasted code part in the post).
Then I call the App class, which fetches the URL(mysite.com/login/user_login) and instantiate a new controller class and run the mentioned method, in this case, it's the first page - MyApp/Contollers/Login.php.
The user_login method fetches the credentials, validate them, and if they are valid, uses the SystemUser object to login.
SystemUser class:
namespace MyApp\Models;
class SystemUser
{
public $id;
# #obj SystemUser profile information (fullname, email, last_login, profile picture, etc')
protected $systemUserDetatils;
public function __construct($systemUserId = NULL)
{
# Create systemUserDedatils obj
$this->systemUserDetatils = new \MyApp\Models\SystemUser\SystemUserDetails();
# If system_user passed
if ( $systemUserId ) {
# Set system user ID
$this->id = $systemUserId;
# Get SysUser data
$this->systemUserDetatils->get($this);
} else {
# Check for sysUser id in the session:
$systemUserId = $this->systemUserDetatils->getUserFromSession();
# Get user data from session
if ( $systemUserId ) {
# Set system user ID
$this->id = $systemUserId;
# Get SysUser data
$this->systemUserDetatils->get($this);
}
}
}
}
PHP-DI is working correctly.
In your SystemUser class you are doing:
$this->systemUserDetatils = new \MyApp\Models\SystemUser\SystemUserDetails();
The constructor for SystemUserDetails requires a Database object, which you are not passing.
By calling new directly, you are not using PHP-DI. By doing this you are hiding the dependency, which is exactly what you are supposedly trying to avoid if you want to use a dependency injection system.
If SystemUser depends ("needs") SystemUserDetails, the dependency should be explicit (e.g. declared in its constructor).
Furthermore: You do not need a definitions file for a system like this. And the definitions file you show in your question doesn't follow the best practices recommended by PHP-DI.
Your design is far from perfect, and I'm not sure of your end-goals, but if you did something like this, it could work:
<?php
// src/Database.php
class Database {
public function getDb() : string {
return 'veryDb';
}
}
<?php
// src/SystemUserDetails.php
class SystemUserDetails {
protected $db;
public function __construct(Database $db)
{
$this->db = $db;
}
public function getDetails() {
return "Got details using " . $this->db->getDb() . '.';
}
}
<?php
// src/SystemUser.php
class SystemUser {
protected $details;
public function __construct(SystemUserDetails $details, $userId=null) {
$this->details = $details;
}
public function getUser() {
return "Found User. " .$this->details->getDetails();
}
}
<?php
//init.php
require_once('vendor/autoload.php');
// build the container. notice I do not use a definition file.
$containerBuilder = new \DI\ContainerBuilder();
$container = $containerBuilder->build();
// get SystemUser instance from the container.
$userInstance = $container->get('SystemUser');
echo $userInstance->getUser(), "\n";
Which results in:
Found User. Got details using veryDb.

Is there any way to execute data provider fuction after setupBeforeClass?

I have a unit test class in which I want to instantiate a object from another class in order to that I used setUpBeforeClass() fixtures of phpunit. So if I will use that recently instantiated object directly in test function then its working fine.
If i'll use this object into another function which had been created for data providers. So that object sets to null cause providers always execute first.
Is there a way to call dataProviders just before the test runs, instead?
require_once('Dashboard.php');
Class Someclass extends PHPUnit_Framework_TestCase {
protected static $_dashboard;
public static function setUpBeforeClass()
{
self::$_dashboard = new Dashboard();
self::$_dashboard->set_class_type('Member');
}
/**
* Test Org Thumb Image Existense
* param org profile image : array
* #dataProvider getOrgProfileImages
*/
public function testFieldValidation($a,$b){
//If I call that object function here it will give the result.
//$members = self::$_dashboard->get_members();
//var_dump($members); Printing result as expected
$this->assertTrue(true);
}
public function getOrgProfileImages() : array {
//var_dump(self::$_dashboard);
$members = self::$_dashboard->get_members();
$tmp_array = ['2','2'];
return $tmp_array;
}
public static function tearDownAfterClass()
{
self::$_dashboard = null;
}
}
Error:
The data provider specified for Someclass::testFieldValidation is invalid.
Call to a member function get_members() on null
Please help to mitigate this issue.
Note: since I don't have the source of your Dashboard class, I'm using a random number in the examples below instead
Providers are invoked before any tests are run (and before any hooks, including beforeClass have a chance to run). By far the easiest way to achieve what you're after is to populate that static property on the class load:
use PHPUnit\Framework\TestCase;
/** #runTestsInSeparateProcesses enabled */
class SomeTest extends TestCase
{
public static $_rand = null;
public function provider()
{
$rand = self::$_rand;
var_dump(__METHOD__, getmypid(), 'provided rand', $rand);
return ['rand' => [$rand]];
}
/** #dataProvider provider */
public function testSomething($rand)
{
$this->expectNotToPerformAssertions();
var_dump(__METHOD__, getmypid(), 'tested with', $rand);
}
/** #dataProvider provider */
public function testSomethingElse($rand)
{
$this->expectNotToPerformAssertions();
var_dump(__METHOD__, getmypid(), 'tested with', $rand);
}
}
// this runs before anything happens to the test case class
// even before providers are invoked
SomeTest::$_rand = rand();
Or you could instantiate you dashboard in the provider itself, on the first call:
public function provider()
{
// Instantiate once
if (null === self::$_rand) {
self::$_rand = rand();
}
$rand = self::$_rand;
var_dump(__METHOD__, getmypid(), 'provided rand', $rand);
return ['rand' => [$rand]];
}
#dirk-scholten is right. You SHOULD be creating a new object for each test. It's a GOOD testing practice. Frankly it looks more like you are testing the data and not testing the code, which is fine I guess, it's just not the typical use of PHPUnit. Based on the assumption that you want to make sure every user in the database has a thumbnail image (just guessing), I would go with the following:
<?php
class DashboardDataTest extends PHPUnit\Framework\TestCase {
private $dashboard;
public function setUp() {
$this->dashboard = new Dashboard();
}
/**
* Test Org Thumb Image Existence
* param org profile image : array
*
* #dataProvider getOrgProfileImages
*
* #param int $user_id
*/
public function testThumbnailImageExists(int $user_id){
$thumbnail = $this->dashboard->get_member_thumbnail($user_id);
$this->assertNotNull($thumbnail);
}
public function geOrgUserIDs() : array {
$dashboard = new Dashboard();
// Something that is slow
$user_ids = $dashboard->get_all_the_member_user_ids();
$data = [];
foreach($user_ids as $user_id){
$data[] = [$user_id];
}
return $data;
}
}
Each data provider will get called once and only once before the tests. You do not need a static data fixture on the class because phpunit handles the data fixture for you when you use data providers.

how does this construct method in each class is working?

I am currently working in laravel 5.3. we are following this approach : controller ->service ->repository -> modal . but i do not what are we passing in the construct methods in each class.
in the below codes the flow goes like this: paycontroller -> Merchant service ->MerchantRepository->modal
the first one is paycontroller:
class PayController extends Controller
{
private $merchantService;
private $paymentService;
private $pay_request_field = array(
'orderID', 'hashKey','currencyCode','amount'
);
/**
* Create a new controller instance.
*
* #return void
*/
// public function __construct()
// {
// $this->middleware('auth');
// }
public function __construct(MerchantService $merchantService, PaymentService $paymentService){
$this->merchantService = $merchantService;
$this->paymentService = $paymentService;
}
is the constructor receiving a variable of the MerchantService and Payment service? if so where is the value coming from? im confused here
next is the MerchantService:
class MerchantService
{
private $merchantRepository;
private $merchantConfigRepository;
private $merchantPaymentRepository;
private $merchant;
private $merchantConfig;
private $merchantPayment;
public function __construct(MerchantRepository $merchantRepository, MerchantConfigRepository $merchantConfigRepository, MerchantPaymentRepository $merchantPaymentRepository){
$this->merchantRepository = $merchantRepository;
$this->merchantConfigRepository = $merchantConfigRepository;
$this->merchantPaymentRepository = $merchantPaymentRepository;
}
public function getMerchantById($id){
$this->merchant = $this->merchantRepository->getMerchantById($id);
$this->merchantConfig = $this->merchantConfigRepository->getMerchantConfig($this->merchant->mid);
return $this->merchant->toArray();
then the MerchantRepository:
class MerchantRepository
{
private $merchant;
public function __construct(Merchant $merchant){
$this->merchant = $merchant;
}
public function getMerchantByHash($hashKey="",$status='action'){
return $this->merchant->where([["hashKey","=",trim($hashKey)],["status","=",$status]])->firstOrFail();
}
public function getMerchantById($mid="",$status='action'){
return $this->merchant->where([["mid","=",trim($mid)],["status","=",$status]])->firstOrFail();
}
}
Then finally the Modal:
class Merchant extends Model
{
protected $connection = 'mysql1';
//Table Name
protected $table = 'merchants';
//Primary Key
protected $primaryKey = 'mid';
}
so whats my overall question is, what is going on in this whole process, and the constructors( parameters) where are they coming from.
Thanks in advance
In this example you are initializing the User and Database using the new keyword
Like:
$database = new Database('host', 'user', 'pass', 'dbname');
$user = new User($database);
And using the new keyword you need to manually resolve the dependency of the class you are initializing.
I have just pasted a line from here:
http://php.net/manual/en/language.oop5.basic.php#language.oop5.basic.new
An object will always be created unless the object has a constructor
defined that throws an exception on error. Classes should be defined
before instantiation (and in some cases this is a requirement)
Here for this block of code:
public function __construct(MerchantService $merchantService, PaymentService $paymentService){
$this->merchantService = $merchantService;
$this->paymentService = $paymentService;
}
You are adding it to the constructor of your Controller and you are lucky that all the dirty works are done for you by Laravel. i.e. dependency of the Controller will be automatically resolved for you by Laravel.
Laravel 5 has great dependency injection and you don't need to worry about from where the dependency is resolved.
Just have a look at this dependency Injection
http://slashnode.com/dependency-injection/
I hope you understood the differences.
class User
{
private $database = null;
public function __construct(Database $database) {
$this->database = $database;
}
public function getUsers() {
return $this->database->getAll('users');
}
}
$database = new Database('host', 'user', 'pass', 'dbname');
$user = new User($database);
$user->getUsers();
so in the above example, we are actually initiating a database object and passing it to the class's constructor. so my question is wwhere is this value of $merchant service being initiated and coming from ?
public function __construct(MerchantService $merchantService, PaymentService $paymentService){
$this->merchantService = $merchantService;
$this->paymentService = $paymentService;
}
in the above example of class, we can actually see that the $database is actually initiated outside the class...so i just dont understand where is the $merchantservice being initiated...

Select entity based on session value

I got two entities. One is a WebshopItem entity, the other one is a WebshopPrice entity.
Each time, you are creating a WebshopItem, you are also filling in 3 WebshopPrices. The WebshopPrices are 3 currencies (EUR, USD and GBP).
Based on the currency you selected (and is saved in your session) I want to display the currency you selected. So, if you picked EUR, I of course want to display the EUR price.
What's the general way of doing this in symfony? Should I use a twig extension which returns the price from the WebshopItem object, based on what's in your session? Should I already filter the WebshopPrices from the database?
Looking forward to your best solutions. Thanks!
Entity/WebshopItem.php
class WebshopItem
{
/**
* #var \Doctrine\Common\Collections\Collection
*/
private $prices;
etc....
}
Entity/WebshopItemPrice.php
class WebshopItemPrice
{
/**
* #var integer
*/
private $id;
/**
* #var string
*/
private $currency;
/**
* #var string
*/
private $price;
private $webshopItem;
}
UPDATE
You can use an entity listener too, but in that case you'll need to override the default resolver to get the session in your listener:
src/Your/GreatBundle/Resources/config/services.yml
doctrine.orm.default_entity_listener_resolver:
class: Your\GreatBundle\Listener\EntityListenerResolver
arguments: [#service_container]
src/Your/GreatBundle/Listener/EntityListenerResolver
namespace Your\GreatBundle\Listener;
use Doctrine\ORM\Mapping\EntityListenerResolver as EntityListenerResolverInterface;
use Symfony\Component\DependencyInjection\ContainerInterface;
class EntityListenerResolver implements EntityListenerResolverInterface
{
private $instances = [];
private $container;
public function __construct(ContainerInterface $container)
{
$this->container = $container;
}
public function clear($className = null)
{
if ($className === null) {
$this->instances = [];
return;
}
if (isset($this->instances[$className = trim($className, '\\')])) {
unset($this->instances[$className]);
}
}
public function register($object)
{
if ( ! is_object($object)) {
throw new \InvalidArgumentException(sprintf('An object was expected, but got "%s".', gettype($object)));
}
$this->instances[get_class($object)] = $object;
}
public function resolve($className)
{
if (isset($this->instances[$className = trim($className, '\\')])) {
return $this->instances[$className];
}
// Here we are injecting the entire container to the listeners
return $this->instances[$className] = new $className($this->container);
}
}
You might listen to the Doctrine's postLoad event in a service injected with the user's session:
src/Your/GreatBundle/Resources/config/services.yml
services:
price.listener:
class: Your\GreatBundle\Listener\PriceListener
arguments: [#session]
tags:
- { name: doctrine.event_listener, event: postLoad }
src/Your/GreatBundle/Listener/PriceListener.php
namespace Your\GreatBundle\Listener\PriceListener;
use Symfony\Component\HttpFoundation\Session\SessionInterface;
use Doctrine\ORM\Event\LifecycleEventArgs;
use Your\GreatBundle\Entity\WebshopItem;
class PriceListener
{
private $session;
public function __construct(SessionInterface $session)
{
$this->session = $session;
}
public function postLoad(LifecycleEventArgs $event)
{
$entity = $event->getEntity();
if ($entity instanceof WebshopItem) {
$currency = $this->session->get('currency', 'EUR');
$entity->setCurrency(currency);
}
}
}
src/Your/GreatBundle/Entity/WebshopItem.php
namespace Your\GreatBundle\Entity;
class WebshopItem
{
...
// You don't need to persist this...
private $currency = 'EUR';
public function setCurrency($currency)
{
$this->currency = $currency;
}
public function getPrice()
{
foreach ($this->prices as $price) {
if ($price->getCurrency() === $this->currency) {
return ($price->getPrice();
}
}
return null;
}
}
You can query WebshopItem joined with WebshopItemPrice WHERE WebshopItemPrice.currency = $variableFromSesion. For example:
$queryBuilder
->select('WebshopItem, WebshopItemPrice')
->leftJoin('WebshopItemPrice.prices', 'WebshopItemPrice')
->where('WebshopItemPrice.currency = :currency')
->setParameter('currency', $variableFromSesion)
Where $variableFromSesion is a current user currency stored in session. After executing that query (by getResult() ) you can get price by calling $webshopItem->getPrices() - this should return only one result
The trick is not about how to retrieve the data but what to use to do it. Since this depends on the Request object you should go with something service-ish. If you're sure you'll never never use this elsewhere, then go with the twig extension. If your backend code would use it too then use a service, say MyPricePickerService (and get that in the twig extension). Note on twig extension that I cannot find anything that warrants that a new instance is created for every scope, so upon every call to this operation you should use the injected Container (so not a cached Request, or a previous instance of MyPricePickerService)!

How can I access the configuration of a Zend Framework application from a controller?

I have a Zend Framework application based on the quick-start setup.
I've gotten the demos working and am now at the point of instantiating a new model class to do some real work. In my controller I want to pass a configuration parameter (specified in the application.ini) to my model constructor, something like this:
class My_UserController extends Zend_Controller_Action
{
public function indexAction()
{
$options = $this->getFrontController()->getParam('bootstrap')->getApplication()->getOptions();
$manager = new My_Model_Manager($options['my']);
$this->view->items = $manager->getItems();
}
}
The example above does allow access to the options, but seems extremely round-about. Is there a better way to access the configuration?
I always add the following init-method to my bootstrap to pass the configuration into the registry.
protected function _initConfig()
{
$config = new Zend_Config($this->getOptions(), true);
Zend_Registry::set('config', $config);
return $config;
}
This will shorten your code a little bit:
class My_UserController extends Zend_Controller_Action
{
public function indexAction()
{
$manager = new My_Model_Manager(Zend_Registry::get('config')->my);
$this->view->items = $manager->getItems();
}
}
Since version 1.8 you can use the below code in your Controller:
$my = $this->getInvokeArg('bootstrap')->getOption('my');
Alternatively, instead of using Zend_Registry you could also create a singleton Application class that will contain all application info, with public member functions that allow you to access the relevant data. Below you can find a snippet with relevant code (it won't run as is, just to give you an idea how it can be implemented) :
final class Application
{
/**
* #var Zend_Config
*/
private $config = null;
/**
* #var Application
*/
private static $application;
// snip
/**
* #return Zend_Config
*/
public function getConfig()
{
if (!$this->config instanceof Zend_Config) {
$this->initConfig();
}
return $this->config;
}
/**
* #return Application
*/
public static function getInstance()
{
if (self::$application === null) {
self::$application = new Application();
}
return self::$application;
}
/**
* Load Configuration
*/
private function initConfig()
{
$configFile = $this->appDir . '/config/application.xml';
if (!is_readable($configFile)) {
throw new Application_Exception('Config file "' . $configFile . '" is not readable');
}
$config = new Zend_Config_Xml($configFile, 'test');
$this->config = $config;
}
// snip
/**
* #param string $appDir
*/
public function init($appDir)
{
$this->appDir = $appDir;
$this->initConfig();
// snip
}
public function run ($appDir)
{
$this->init($appDir);
$front = $this->initController();
$front->dispatch();
}
}
Your bootstrap would look like this :
require 'Application.php';
try {
Application::getInstance()->run(dirname(dirname(__FILE__)));
} catch (Exception $e) {
header("HTTP/1.x 500 Internal Server Error");
trigger_error('Application Error : '.$e->getMessage(), E_USER_ERROR);
}
When you want to access the configuration you would use the following :
$var = Application::getInstance()->getConfig()->somevar;
In most ZF apps, the application object is declared in the global scope (see public/index.php in apps created with ZFW_DISTRIBUTION/bin/zf.sh).
It's not exactly the ZF way, but you can access the object with $GLOBALS['application'].
It kinda feels like cheating, but if you're after performance, this will likely be the quickest option.
$manager = new My_Model_Manager($GLOBALS['application']->getOption('my'));
$this->getInvokeArg('bootstrap')->getOptions();
// or
$configDb = $this->getInvokeArg('bootstrap')->getOption('db');
I've define a short hand in some place I require_once() in the beginning of boostrap:
function reg($name, $value=null) {
(null===$value) || Zend_Registry::set($name, $value);
return Zend_Registry::get($name);
}
and in the bootstrap I have a:
protected function _initFinal()
{
reg('::app', $this->getApplication());
}
then I can get the Application instance anywhere by use:
$app = reg('::app');
A really simple way to access the configuration options is by directly accessing the globally defined $application variable.
class My_UserController extends Zend_Controller_Action {
public function indexAction() {
global $application;
$options = $application->getOptions();
}
}

Categories