Pass array to constructor in PHP - php

I am fiddling with this issue and cannot resolve it - just wanted to check if anyone here can help with tips
I am loading the class and calling the constructor like this
include_once './Myaws.php';
$aws = new Myaws();
$aws->bucket = $images['config']['bucket'];
Myaws.php is as follows
class Myaws {
public $bucket;
function __construct() {
$this->aws = Aws::factory('./config/aws_config.php');
}
}
It works like a charm!
Now the issue
The './config/aws_config.php' is just an array that will change depending on the deployment stage - so I want to make it dynamic. Here is what I do and it doesnt work
include_once './Myaws.php';
$aws = new Myaws();
$aws->bucket = $images['config']['bucket'];
$aws->config = $images['config']['awsconfig'];
And in the Myaws.php, I change the following
class Myaws {
public $bucket;
public $config;
function __construct() {
$this->aws = Aws::factory($this->config);
}
}
It doesn't work :( and neither does the below one
include_once './Myaws.php';
$aws = new Myaws($images['config']['awsconfig']);
$aws->bucket = $images['config']['bucket'];
class Myaws {
public $bucket;
function __construct($config) {
$this->aws = Aws::factory($config);
}
}
This is pretty basic Oops and I don't seem to get it I think. Can anyone suggest me how can I make that variable $config dynamic?

I found the formatting on the included file vs in a passed array to be not 100% compatible. Also check the in the api docs how they use my_profile to pass those credentials.
here is a example of the current method I am using to generation the config
$aws = Aws::factory($this->getAwsConfig());
private function getAwsConfig()
{
return array(
// Bootstrap the configuration file with AWS specific features
'credentials' => array(
'key' => $this->awsKey,
'secret' => $this->awsSecret
),
'includes' => array('_aws'),
'services' => array(
// All AWS clients extend from 'default_settings'. Here we are
// overriding 'default_settings' with our default credentials and
// providing a default region setting.
'default_settings' => array(
'params' => array(
'region' => $this->awsRegion
)
)
)
);
}

Related

Overriding Yii components in the controller

I have a Yii 1.x component loaded in the configuration file like so
$config['components']['simplesamlphp'] = array(
'class' => 'application.components.yii-simplesamlphp.components.Simplesamlphp',
'autoloadPath' => SAML_DIR.'/test2/lib/_autoload.php',
'authSource' => 'default-sp',
);
I need to make the autoloadPath property dynamic based on who the user is in the controller. Is this possible? And if so how do I overwrite it?
Probably the best way is to extend Simplesamlphp and configure property in init():
class MySimplesamlphp extends Simplesamlphp {
public $adminAutoloadPath;
public $nonAdminAutoloadPath;
public function init() {
if (Yii::app()->user->isAdmin()) {
$this->autoloadPath = $this->adminAutoloadPath;
} else {
$this->autoloadPath = $this->nonAdminAutoloadPath;
}
parent::init();
}
}
And use new component in config:
$config['components']['simplesamlphp'] = array(
'class' => 'MySimplesamlphp',
'adminAutoloadPath' => SAML_DIR.'/test2-admin/lib/_autoload.php',
'nonAdminAutoloadPath' => SAML_DIR.'/test2/lib/_autoload.php',
'authSource' => 'default-sp',
);
I figured it out overriding yii components is fairly easy even if you dont initialize it in the config.
$component = array(
'class' => 'application.components.yii-simplesamlphp.components.Simplesamlphp',
'autoloadPath' => SAML_DIR.'/'.$tenant_path.'/lib/_autoload.php',
'authSource' => 'default-sp',
); //where $tenant_path is the directory of the component i need based on the tenant
Yii::app()->setComponent('simplesamlphp',$component);
then use the component in your controller like so
Yii::app()->simplesamlphp;
Note that you will only have access to the component within your controller method so all i did was move the that code to its own class and call it when i needed to create a new instance of the component

PrestaShop 1.7 Add new resources and class

I created new resources with this code:
class WebserviceRequest extends WebserviceRequestCore {
public static function getResources(){
$resources = parent::getResources();
// if you do not have class for your table
$resources['test'] = array('description' => 'Manage My API', 'specific_management' => true);
$resources['categoryecommerce'] = array('description' => 'o jacie marcin', 'class' => 'CategoryEcommerce');
$mp_resource = Hook::exec('addMobikulResources', array('resources' => $resources), null, true, false);
if (is_array($mp_resource) && count($mp_resource)) {
foreach ($mp_resource as $new_resources) {
if (is_array($new_resources) && count($new_resources)) {
$resources = array_merge($resources, $new_resources);
}
}
}
ksort($resources);
return $resources;
}
}
And new class:
class CategoryEcommerceCore extends ObjectModelCore {
public $category_id;
public $category_core_id;
public static $definition = array(
'table' => "category_ecommerce",
'primary' => 'category_id',
'fields' => array(
'category_core_id' => array('type' => self::TYPE_INT),
)
);
protected $webserviceParameters = array();
}
Webservice is override properly. My class WebserviceRequest is copying to
/override/classes/webservice/WebserviceRequest
but class isn't copying to /override/classes/ when i installing my module.
How to add new resourcess with own logic ? I want to add categories within relation to my table.
Regards
Martin
As soon as there is literally nothing regarding the API except Webkul tutorial... I tried to implement the "Webkul's" tutorial, but also failed. However seems that it's better to use hooks instead of overrides. I used my "reverse engineering skills" to determine the way to create that API, so-o-o-o, BEHOLD! :D
Let's assume you have a custom PrestaShop 1.7 module. Your file is mymodule.php and here are several steps.
This is an install method wich allows you to register the hook within database (you can uninstall and reinstall the module for this method to be executed):
public function install() {
parent::install();
$this->registerHook('addWebserviceResources');
return true;
}
Add the hook listener:
public function hookAddWebserviceResources($resources) {
$added_resources['test'] = [
'description' => 'Test',
'specific_management' => true,
];
return $added_resources;
}
That specific_management option shows you are going to use WebsiteSpecificManagement file instead of database model file.
Create WebsiteSpecificManagement file, called WebsiteSpecificManagementTest (Test - is CamelCased name of your endpoint). You can take the skeleton for this file from /classes/webservice/WebserviceSpecificManagementSearch.php. Remove everything except:
setObjectOutput
setWsObject
getWsObject
getObjectOutput
setUrlSegment
getUrlSegment
getContent (should return $this->output; and nothing more)
manage - you should rewrite it to return/process the data you want.
Add
include_once(_PS_MODULE_DIR_.'YOURMODULENAME/classes/WebserviceSpecificManagementTest.php');
to your module file (haven't figured out how to include automatically).
Go to /Backoffice/index.php?controller=AdminWebservice and setup the new "Auth" key for your application, selecting the test endpoint from the permissions list. Remember the key.
Visit /api/test?ws_key=YOUR_KEY_GENERATED_ON_STEP_4 and see the XML response.
Add &output_format=JSON to your URL to see the response in JSON.
You have to use something like $this->output = json_encode(['blah' => 'world']) within manage method at WebsiteSpecificManagementTest.

How can I use Doctrine 2's console tools with dynamically generated EntityManagers?

We are using Doctrine 2 in our app, but due to our infrastructure, we do not have a static configuration for database connections. Instead, we have a collection of singletons in a service provider for each database we need to connect to, and we select a random database host for then when we connect.
Unfortunately, we are seeing some performance degradation in Doctrine's getRepository() function. I believe the issue is that Doctrine needs to generate its proxy classes at runtime (even in production) because we cannot figure out how to configure the CLI tools in order to create them at build time.
We are using the Laravel framework for the application.
Here's an example of our Laravel service provider which makes the repositories available for dependency injection.
<?php
use App\Database\Doctrine\Manager as DoctrineManager;
use Proprietary\ConnectionFactory;
use App\Database\Entities;
use App\Database\Repositories;
use App\Database\Constants\EntityConstants;
class DoctrineServiceProvider extends ServiceProvider
{
// Create a singleton for the Doctrine Manager. This class will handle entity manager generation.
$this->app->singleton(DoctrineManager::class, function ($app)
{
return new DoctrineManager(
$app->make(ConnectionFactory::class),
[
EntityConstants::ENTITY_CLASS_DATABASE1 => [app_path('Database/Entities/Database1')],
EntityConstants::ENTITY_CLASS_DATABASE2 => [app_path('Database/Entities/Database2')],
],
config('app.debug'),
$this->app->make(LoggerInterface::class)
);
});
// Register the first repository
$this->app->singleton(Repositories\Database1\RepositoryA1::class, function ($app)
{
return $app[DoctrineManager::class]
->getEntityManager(EntityConstants::ENTITY_CLASS_DATABASE1)
->getRepository(Entities\Database1\RepositoryA1::class);
});
// Register the second repository
$this->app->singleton(Repositories\Database1\RepositoryA2::class, function ($app)
{
return $app[DoctrineManager::class]
->getEntityManager(EntityConstants::ENTITY_CLASS_DATABASE1)
->getRepository(Entities\Database1\RepositoryA2::class);
});
// Register a repository for the second database
$this->app->singleton(Repositories\Database2\RepositoryB1::class, function ($app)
{
return $app[DoctrineManager::class]
->getEntityManager(EntityConstants::ENTITY_CLASS_DATABASE2)
->getRepository(Entities\Database2\RepositoryB1::class);
});
}
Here's the class that generates EntityManagers for Doctrine:
<?php
use Doctrine\ORM\Tools\Setup;
use Doctrine\ORM\EntityManager;
use Doctrine\DBAL\DriverManager;
use Doctrine\DBAL\Connections\MasterSlaveConnection;
use Proprietary\ConnectionFactory;
class Manager
{
private $c_factory;
private $paths;
private $connections = [];
private $entity_managers = [];
public function __construct(
ConnectionFactory $cf,
array $paths
)
{
$this->c_factory = $cf;
$this->paths = $paths;
}
public function getConnection($name, $partition = false, $region = false)
{
// Get a list of servers for this database and format them for use with Doctrine
$servers = self::formatServers($name, $this->c_factory->getServers($name, true, $partition, $region));
// Generate a connection for the entity manager using the servers we have.
$connection = DriverManager::getConnection(
array_merge([
'wrapperClass' => MasterSlaveConnection::class,
'driver' => 'pdo_mysql',
], $servers)
);
return $connection;
}
public function getEntityManager($name, $partition = false, $region = false)
{
// Should these things be cached somehow at build time?
$config = Setup::createAnnotationMetadataConfiguration($this->paths[$name], false);
$config->setAutoGenerateProxyClasses(true);
// Set up the connection
$connection = $this->getConnection($name, $partition, $region);
$entity_manager = EntityManager::create($connection, $config);
return $entity_manager;
}
// Converts servers from a format provided by our proprietary code to a format Doctrine can use.
private static function formatServers($db_name, array $servers)
{
$doctrine_servers = [
'slaves' => [],
];
foreach ($servers as $server)
{
// Format for Doctrine
$server = [
'user' => $server['username'],
'password' => $server['password'],
'host' => $server['hostname'],
'dbname' => $db_name,
'charset' => 'utf8',
];
// Masters can also be used as slaves.
$doctrine_servers['slaves'][] = $server;
// Servers are ordered by which is closest, and Doctrine only allows a
// single master, so if we already set one, don't overwrite it.
if ($server['is_master'] && !isset($doctrine_servers['master']))
{
$doctrine_servers['master'] = $server;
}
}
return $doctrine_servers;
}
}
Our service classes use dependency injection to get the repository singletons defined in the service provider. When we use the singletons for the first time, Doctrine will use the entity class defined in the service provider and get the connection associated with the repository.
Is there any way we can enable the CLI tools with this configuration? Are there any other ways that we can optimize this for use in production?
Thanks.
I was able to solve the problem thanks to a suggestion from the Doctrine IRC channel. Since the CLI tools can only handle a single database, I created a doctrine-cli directory containing a base-config.php file and a subdirectory for each of the databases we use.
Here's an example file structure:
doctrine-cli/
|- database1/
| |- cli-config.php
|- database2/
| |- cli-config.php
|- base-config.php
The base-config.php file looks like this:
<?php
use Symfony\Component\Console\Helper\HelperSet;
use Doctrine\DBAL\Tools\Console\Helper\ConnectionHelper;
use Doctrine\ORM\Tools\Console\Helper\EntityManagerHelper;
use App\Database\Doctrine\Manager as DoctrineManager;
use Proprietary\ConnectionFactory;
require __DIR__ . '/../bootstrap/autoload.php';
class DoctrineCLIBaseConfig
{
private $helper_set;
public function __construct($entity_constant, $entity_namespace)
{
$app = require_once __DIR__ . '/../bootstrap/app.php';
// Proprietary factory for getting our databse details
$connection_factory = new ConnectionFactory(...);
// Our class that parses the results from above and handles our Doctrine connection.
$manager = new DoctrineManager(
$connection_factory,
[$entity_constant => [app_path('Database/Entities/' . $entity_namespace)]],
false,
null,
null
);
$em = $manager->getEntityManager($entity_constant);
$this->helper_set = new HelperSet([
'db' => new ConnectionHelper($em->getConnection()),
'em' => new EntityManagerHelper($em),
]);
}
public function getHelperSet()
{
return $this->helper_set;
}
}
Here's an example cli-config.php from the database directory:
<?php
use App\Database\Constants\EntityConstants;
require __DIR__ . "/../base-config.php";
$config = new DoctrineCLIBaseConfig(
EntityConstants::ENTITY_CLASS_DATABASE1,
"database1"
);
return $config->getHelperSet();
Now, I'm able to cycle through each of the directories and run commands like so:
php ../../vendor/bin/doctrine orm:generate-proxies
For our build process, I wrote a simple shell script that cycles through the directories and runs the orm:generate-proxies command.

What settings should I use for db if I only want to use MongoDB in PhalconPHP?

I created a simple Phalcon project using Phalcon DevTools (1.2.3).
Now I want to use MongoDB for the database. How do I set this up correctly?
I came this far (see code below):
This is my config.php
<?php
return new \Phalcon\Config(array(
'database' => array(
'adapter' => 'Nosql', //Was 'Mysql', but Nosql is not supported?
'host' => 'localhost',
'username' => 'root',
'password' => '',
'dbname' => 'test',
),
'application' => array(
'controllersDir' => __DIR__ . '/../../app/controllers/',
'modelsDir' => __DIR__ . '/../../app/models/',
'viewsDir' => __DIR__ . '/../../app/views/',
'pluginsDir' => __DIR__ . '/../../app/plugins/',
'libraryDir' => __DIR__ . '/../../app/library/',
'cacheDir' => __DIR__ . '/../../app/cache/',
'baseUri' => 'localhost/',
)
));
This is my services.php
<?php
use Phalcon\DI\FactoryDefault,
Phalcon\Mvc\View,
Phalcon\Mvc\Url as UrlResolver,
//Phalcon\Db\Adapter\Pdo\Mysql as DbAdapter, //Do I need this when I use Mongo?
Phalcon\Mvc\View\Engine\Volt as VoltEngine,
Phalcon\Mvc\Model\Metadata\Memory as MetaDataAdapter,
Phalcon\Session\Adapter\Files as SessionAdapter;
/**
* The FactoryDefault Dependency Injector automatically register the right services providing a full stack framework
*/
$di = new FactoryDefault();
/**
* The URL component is used to generate all kind of urls in the application
*/
$di->set('url', function() use ($config) {
$url = new UrlResolver();
$url->setBaseUri($config->application->baseUri);
return $url;
}, true);
/**
* Setting up the view component
*/
$di->set('view', function() use ($config) {
$view = new View();
$view->setViewsDir($config->application->viewsDir);
$view->registerEngines(array(
'.volt' => function($view, $di) use ($config) {
$volt = new VoltEngine($view, $di);
$volt->setOptions(array(
'compiledPath' => $config->application->cacheDir,
'compiledSeparator' => '_'
));
return $volt;
},
'.phtml' => 'Phalcon\Mvc\View\Engine\Php'
));
return $view;
}, true);
/**
* Database connection is created based in the parameters defined in the configuration file
*/
$di->set('mongo', function() use ($config) {
$mongo = new Mongo();
return $mongo->selectDb($config->database->dbname);
});
/**
* If the configuration specify the use of metadata adapter use it or use memory otherwise
*/
$di->set('modelsMetadata', function() {
return new MetaDataAdapter();
});
/**
* Start the session the first time some component request the session service
*/
$di->set('session', function() {
$session = new SessionAdapter();
$session->start();
return $session;
});
I altered the standard mysql db connection to be mongo, using the documentation.
But now I have to set up my database adapter in Config, but Nosql doesn't seem to work. DevTools throws this error in the terminal when trying to create a model:
Error: Adapter Nosql is not supported
When I do put in ' Mysql' for the adapter in the config and try to create a model, this is the error I get:
Error: SQLSTATE[HY000] [2002] No such file or directory
Does it need the Mysql adapter to be set in order to use Mongo/Nosql? Or should I put in something else for the adapter/config? Any ideas?
within service.php file where you have mongo service registered
$di->set('mongo', function() {
$mongo = new Mongo();
return $mongo->selectDb("DB_NAME");
}, true);
below that put following lines of code,
$di->set('collectionManager', function(){
return new Phalcon\Mvc\Collection\Manager();
}, true);
After the above is done you need to ensure that your model is extending from \Phalcon\Mvc\Collection
E.g. Customers.php
class Customers extends \Phalcon\Mvc\Collection
{
public $name;
public $email;
}
Once above is done, you can verify if everything is working fine as follows
$robot = new Customers();
$robot->email= "abc#test.com";
$robot->name = "XYZ";
if ($robot->save() == false)
{
echo "Could not be Saved!!";
}
else
{
echo "Data Saved!!";
}
You can put above code in any Controller-Action and try.
If everything goes well, you should be able to see one document created within Customer collection within your database of MongoDB.
Refer http://docs.phalconphp.com/en/latest/reference/odm.html for more..
$di->set('mongo', function() {
$user = 'blog';
$password = 'blog';
$host = 'localhost';
$port = '27017';
$db = 'blog';
$cn = sprintf('mongodb://%s:%d/%s',$host,$port,$db);
$con = new Mongo($cn,array('username'=>$user,'password'=>$password));
return $con->selectDB($db);
}, true);
As of the latest PhalconPHP, MongoDB seems to be a supported option for cache only, not for using as a replacement for the database.
It looks there is no MongoDB adapter for the Config component, only MySQL and couple of others (text based) in the incubator (https://github.com/phalcon/incubator).
You can still use MongoDB for the ACL and your Models though, see https://github.com/phalcon/incubator/tree/master/Library/Phalcon/Acl/Adapter and http://docs.phalconphp.com/en/latest/reference/odm.html#

ding integration with zend framework

We're using ZendFramework at my workplace for our webapps. It's ok, but it lacks some of the best modern practices (like dependency injection and inversion of control, aop, etc).
For a couple of months, I've been (on my own) using Ding framework as a container for DI and AOP as a test drive. I really like it, so I'd like to bring it into our projects.
But how? So there's the question: how to properly integrate Ding in Zend Framework applications? considering ZF controllers cant be beans (as they are instantiated right from the dispatcher), how to propertly inject all dependencies in them?
P.s: Not using Zend Framework is not an option (at least in the middle term).
P.P.S: Anyone care to add "ding" as a new tag?
I'm glad Ding is helping you.
I contributed on this project and also needed to integrate with a Zend Framework application. I used Zend's application resources and plugin system to achieve this.
An application resource (you can reuse among projects)
<?php
class Application_Resource_Ding extends Zend_Application_Resource_ResourceAbstract
{
protected $_options = array(
'factory' => array(
'bdef' => array(
'xml' => array(
'filename' => array('beans.xml')
),
),
),
'cache' => array(
'proxy' => array('impl' => 'dummy'),
'bdef' => array('impl' => 'dummy'),
'beans' => array('impl' => 'dummy')
)
);
public function init()
{
// set default config dir before mergin options (cant be set statically)
$this->_options['factory']['bdef']['xml']['directories'] = array(APPLICATION_PATH .'/configs');
$options = $this->getOptions();
// parse factory properties (if set)
if (isset($options['factory']['properties'])) {
$options['factory']['properties'] = parse_ini_file(
$options['factory']['properties']
);
}
// change log4php_properties for log4php.properties (if exists)
if (isset($options['log4php_properties'])) {
$options['log4php.properties'] = $options['log4php_properties'];
unset($options['log4php_properties']);
}
$properties = array(
'ding' => $options
);
return Ding\Container\Impl\ContainerImpl::getInstance($properties);
}
}
An action helper to use inside the controllers:
<?php
class Application_Action_Helper_Ding extends Zend_Controller_Action_Helper_Abstract
{
protected $ding = null;
public function init()
{
// just once...
if (null !== $this->ding) {
return;
}
// get ding bootstrapped resource
$bootstrap = $this->getActionController()->getInvokeArg('bootstrap');
$ding = $bootstrap->getResource('ding');
if (!$ding) {
throw new Zend_Controller_Action_Exception(
'Ding resource not bootstrapped'
);
}
$this->ding = $ding;
}
public function getBean($bean)
{
return $this->ding->getBean($bean);
}
public function direct($bean)
{
return $this->getBean($bean);
}
}
In your application.ini you should add something like this (plus any extra configuration you need)
resources.frontController.actionHelperPaths.Application_Action_Helper = "Application/Action/Helper"
resources.ding.factory.properties = APPLICATION_PATH "/configs/ding.properties"
resources.ding.log4php_properties = APPLICATION_PATH "/configs/log4php.properties"
And then in your controllers, to request a bean:
$service = $this->_helper->ding('someService');
Hope this helps!

Categories