I have created a simple custom Component that extends from yii\base\Component.
namespace app\components\managers;
use yii\base\Component;
use yii\base\InvalidConfigException;
class HubspotDataManager extends Component
{
public $hubspotApiKey;
private $apiFactory;
public function init()
{
if (empty($this->hubspotApiKey)) {
throw new InvalidConfigException('Hubspot API Key cannot be empty.');
}
parent::init();
// initialise Hubspot factory instance after configuration is applied
$this->apiFactory = $this->getHubspotApiFactoryInstance();
}
public function getHubspotApiFactoryInstance()
{
return new \SevenShores\Hubspot\Factory([
'key' => $this->hubspotApiKey,
'oauth' => false, // default
'base_url' => 'https://api.hubapi.com' // default
]);
}
}
I have registered the component in my config/web.php application config, where I have also added a custom parameter.
'components' => [
...
'hubspotDataManager' => [
'class' => app\components\managers\HubspotDataManager::class,
'hubspotApiKey' => 'mycustomkeystringhere',
],
...
],
However, I find that when I instantiate my component like so:
$hubspot = new HubspotDataManager();
this hubspotApiKey config parameter is not passed into the __construct($config = []) - $config is just an empty array, so in init() the config does not set the component hubspotApiKey property the the value of hubspotApiKey in the config, so accordingly I see this from my thrown exception:
Invalid Configuration – yii\base\InvalidConfigException
Hubspot API Key cannot be empty.
However, if I call up the component like so:
Yii::$app->hubspotDataManager
it does pass this config variable in! Why is this? What extra legwork must I do to get the component to load it's application config data for standard class instantiation? I cannot find anything about this particular scenario in the docs.
NOTE: Using latest Yii2 version 2.0.15.1 using basic application template.
When you create an instance without using the Service Locator, the configuration is of course not known.
The flow is like this, Yii::$app is a Service Locator. It will pass the configuration to the Dependency Injector containter Yii::$container.
If you want to pass the config without using the Service Locator Yii::$app, you could set the container:
Yii::$container->set(app\components\managers\HubspotDataManager::class, [
'hubspotApiKey' => 'mycustomkeystringhere',
]);
and
$hubspot = Yii::$container->get(app\components\managers\HubspotDataManager::class);
the result would be the same as using the service locator Yii::$app.
You could also instantiate the a new instance of the class like this and pass the configuration to it.
$hubspot = new HubspotDataManager([
'hubspotApiKey' => 'mycustomkeystringhere',
]);
Related
I'm using the custom module in my project, and it was working fine with Geolocation 1.11 module.
After I've updated Geolocation to 3.7 my custom module stopped working.
What I've found - my custom module was using trait from 'GoogleMapsDisplayTrait.php' and now it is missing in Geolocation. It was like that
class LocationsMapBlock extends BlockBase {
use GoogleMapsDisplayTrait;
public function build() {
return [
'#theme' => 'locations_map',
'#attached' => [
'library' => ['location/map'],
'drupalSettings' => [
'geolocation' => [
'google_map_url' => $this->getGoogleMapsApiUrl(),
],
'locations' => $this->getLocationMapData(),
],
],
];
}
}
I've found that now most similar class to trait GoogleMapsDisplayTrait) is inside geolocation_google_maps submodule of geolocation module.
But now it's not a trait, but abstract class with the same methods as previous trait was.
abstract class GoogleMapsProviderBase extends MapProviderBase {
...
}
I've tried to add this class:
use Drupal\geolocation_google_maps\GoogleMapsProviderBase;
But now I'm receiving the error
'Error: Call to undefined method Drupal\location\Plugin\Block\LocationsMapBlock::getGoogleMapsApiUrl() in Drupal\location\Plugin\Block\LocationsMapBlock->build() (line 32 of modules/custom/location/src/Plugin/Block/LocationsMapBlock.php).'
My PHP knowledges is to weak to find the solution...
The undefined function getGoogleMapsApiUrl() is, maybe the file is missing?
Check if the file exists:
/modules/geolocation/modules/geolocation_google_maps/src/GoogleMapsProviderBase.php
Try to install and enable the following modules for a cleaner working with geolocation - specially for the geolocation_google_maps:
geofield
geolocation_geofield
geolocation_google_maps
Try using this call instead of $this->getGoogleMapsApiUrl():
Drupal::service('plugin.manager.geolocation.mapprovider')->getMapProvider('google_maps')->getGoogleMapsApiUrl()
I have Zend Framework 3 Application with working translator using po files.
I have configured it like this in my \config\global.php file:
'translator' => [
'locale' => 'en_US',
'translation_file_patterns' => [
[
'type' => 'gettext',
'base_dir' => getcwd() . '/data/language/',
'pattern' => '/%s/general.mo',
],
],
],
When i change the value of the "locale" it works ok and finds the proper .po file.
I need to be able to set the locale depending on a user profile's value saved in the database.
I have checked the documentation from here http://zendframework.github.io/zend-i18n/translation/ and the tutorial from here https://docs.zendframework.com/tutorials/i18n/ but they just mention the setLocale() method with no explanation or example. There is similar thread here Zend framework 2 : How to set locale globaly? but it's for ZF2 and it doesn't provide working solution just some suggestions.
To summarize my question - how and where should i use the setLocale() method so it would be effective in the whole application and $this->translate($message) in all view files will use the new locale instead the default one used in the configuration file?
You just need to set the PHP locale. To do so, use \Locale::setDefault('en-GB');.
Have a look at SlmLocale, this specific file is where it's done.
While that was the easiest way, you could also use the setLocale function on the MvcTranslator I guess. For that, you would need to override the existing factory with your own factory, therefore decorating the original one.
If you look at the ConfigProvider file in zend-mvc-i18n, you can see that aliases and factories are used here to create the MVC translator. Then you can see how the factory in question works, it basically creates a decorate translator, as stated in the doc.
By default, the service manager always provide the same instance (shared service), just like a singleton.
What we will therefore do is override this configuration (ie. make sure your own module is after the Zend\Mvc\I18n in modules.config.php). Then, in the module configuration, we can provide our own translator.
Our translator basically consist of the translator from the documentation, on which the setLocale is called. In order to do so, we can use a delegator.
return [
'factories' => [
TranslatorInterface::class => TranslatorServiceFactory::class,
],
'delegators' => [
TranslatorInterface::class => [
\Application\Factory\TranslatorFactory::class,
],
],
];
And then the TranslatorFactory:
use Interop\Container\ContainerInterface;
use Zend\ServiceManager\Factory\DelegatorFactoryInterface;
class TranslatorFactory implements DelegatorFactoryInterface
{
public function __invoke(ContainerInterface $container, $name, callable $callback, array $options = null)
{
$translator = call_user_func($callback);
$translator->setLocale('en-GB');
return $translator;
}
}
That would be one way to do it (you get the container in that factory, so you could get some user data probably).
Another solution is to use the event system, and only declare the locale in the event listener where you retrieve your user details.
On my module.config.php I've got something like:
return [
'view_helpers' => [
'invokables' => [
'mycustomviewhelper' => 'Namespace\View\Helper\MyCustomViewHelper',
],
],
];
I have also got a utility class that will handle the responsibility of rendering a helper. Something like Zend\Paginator.
Zend\Paginator has a __toString() method that proxies to render() call, which instantiates View\Renderer\PhpRenderer() and then calls $view->paginationControl($this).
I am trying to replicate the similar functionality in my utility class, which has similar strategy to what Zend\Paginator already does, the only thing being different is my view helper is a custom one. Hence, my code looks like:
$view->MyCustomViewHelper($this);
This does not work, because the PhpRenderer ignores the config defined manually and does the following in getHelperPluginManager:
$this->setHelperPluginManager(new HelperPluginManager());
I've tried invoking the helpers already defined in ViewHelperManager and this works well.
I did try merging in the config beforehand and then setting the PhpRenderer in the view but then this caused other problems, such as my partials were not found etc.
Now my question is why does ZF not consider any custom registered views when trying to render it in isolation. Is there any other way to do this?
Thank you.
Right, after a bit of a debugging, and playing with the configs, I was able to make this work. Still not sure if this is the best way to do this, but looks like currently there's no other way to make it work.
I created a factory for the utility class, instantiated the PhpRenderer, and then merged in my config with the ViewPluginManager manually. My factory now looks like:
public function createService(ServiceLocatorInterface $serviceLocatorInterface)
{
$dataTable = new DataTable;
$phpRenderer = new PhpRenderer();
$config = new \Zend\ServiceManager\Config([
'invokables' => [
'datatablerenderer' => 'DataTable\View\Helper\DataTableRenderer'
],
]);
$phpRenderer->setHelperPluginManager(new HelperPluginManager($config));
$dataTable->setView($phpRenderer);
return $dataTable;
}
However will have to refactor this so that the config comes from the view_helpers config key and is not hardcoded.
I'm trying to integrate this PHP framework https://github.com/panique/mini with Amazon S3:s configuration file with the service builder http://docs.aws.amazon.com/aws-sdk-php/guide/latest/credentials.html#using-a-configuration-file-with-the-service-builder
Best would be if I could integrate it with the existing config.php https://github.com/panique/mini/blob/master/application/config/config.php but I don't know how I should do with this line.
$aws = Aws::factory('/path/to/custom/config.php');
Since I already include config.php in another part of the code
This is what I have tried but don't know why it does not work
Created a new file aws-config.php in the folder config and included it in my project. aws-config.php have the following code (with my correct keys).
return array(
// Bootstrap the configuration file with AWS specific features
'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(
array(
'credentials' => array(
'key' => 'YOUR_AWS_ACCESS_KEY_ID',
'secret' => 'YOUR_AWS_SECRET_ACCESS_KEY',
)
),
'region' => 'us-west-1'
)
)
)
);
I want to access my credentials in my controller that looks like this: https://github.com/panique/mini/blob/master/application/controller/songs.php
I've implemented it like this from the documentation
<?php
use Aws\S3\S3Client;
use Aws\Common\Aws;
// Create the AWS service builder, providing the path to the config file
$aws = Aws::factory(APP . 'config/aws-config.php');
$client = $aws->get('s3');
class Album extends Controller
{
public function index()
{
foreach ($images as &$image) {
$image->imageThumbnailUrl = $client->getObjectUrl($resizedBucket, 'resized-'.$image->image_name, '+10 minutes');
}
...
...
I get the error message
Notice: Undefined variable: client in Fatal error: Call to a member
function getObjectUrl() on a non-object in
I use $client and getObjectUrl in my loop.
My code works fine if I use "Passing credentials into a client factory method" http://docs.aws.amazon.com/aws-sdk-php/guide/latest/credentials.html#passing-credentials-into-a-client-factory-method in the index method in my controller.
The problem here has nothing to do with the AWS SDK or the panique/mini framework. You cannot declare variables outside of a class definition and expect to be able to use them inside the class definition. That is just how variable scoping works in PHP. You need to pass the s3Client object into the Controller somehow, or instantiate it inside of the controller.
You can literally move these lines into your index method, and it should work.
// Create the AWS service builder, providing the path to the config file
$aws = Aws::factory(APP . 'config/aws-config.php');
$client = $aws->get('s3');
I am developing an component that will take a GET variable from the URL, store it in an accessible variable and place it in a cookie. If the GET variable is not set it will load the cookie value into the accessible variable:
MyComponent extends ApplicationComponent {
protected $_var = null;
public init(){
// if isset($_GET['var']), set value to $_var and cookie;
// elseif cookie set value to $_var;
// else nothing;
}
public getVar(){
return $_var;
}
}
I always want one instance of the component and I want to run init on every frontend request (even if it is not explicitly referred to).
How do I hook this up? I am aware of the onBeginRequest, but doesn't this only allow static methods?
I could hack it in and set an app component in a separate method, but that doesn't sit well.. I'd like this to be portable across sites and set-up in my config if possible.
You can just add it to the preload section of your config:
protected/config/main.php
return array(
// some parameters
'preload' => array( 'myComponent' ),
'components' => array(
'myComponent' => array(
'class' => 'path.to.your.component.MyComponent'
),
),
);
This will automatically instantiate the component on each frontend request. Please refer to the corresponding section of The Definitive Guide to Yii.