Loading core scripts such as jQuery in Yii 2 - php

I've been having a hard time trying to figure out how to load jQuery or other CORE scripts in Yii 2.
In Yii 1 it seemed this was the way:
<?php Yii::app()->clientScript->registerCoreScript("jquery"); ?>
In Yii 2, $app is a property of Yii, not a method, so the above naturally doesn't work, but changing it to:
<?php Yii::$app->clientScript->registerCoreScript("jquery"); ?>
produces this error:
Getting unknown property: yii\web\Application::clientScript
I couldn't find any documentation for Yii 2 about loading core scripts, so I tried the below:
<?php $this->registerJsFile(Yii::$app->request->baseUrl . '/js/jquery.min.js', array('position' => $this::POS_HEAD), 'jquery'); ?>
Whilst this loads jQuery in the head, a second version of jQuery is also loaded by Yii when needed and hence causes conflict errors.
Additionally, I don't want to use Yii's implementation of jQuery, I would prefer to maintain my own and hence that is why I am doing this.
How can I load jQuery and other core files without Yii loading duplicate copies of them when it needs them?

In order to disable Yii2's default assets you can refer to this question:
Yii2 disable Bootstrap Js, JQuery and CSS
Anyway, Yii2's asset management way is different from Yii 1.x.x. First you need to create an AssetBundle. As official guide example, create an asset bundle like below in ``:
namespace app\assets\YourAssetBundleName;
use yii\web\AssetBundle;
class YourAssetBundleName extends AssetBundle
{
public $basePath = '#webroot';
public $baseUrl = '#web';
public $css = [
'path/file.css',//or files
];
public $js=[
'path/file.js' //or files
];
//if this asset depends on other assets you may populate below array
public $depends = [
];
}
Then, to publish them on your views:
use app\assets\YourAssetBundleName;
YourAssetBundleName::register($this);
Which $this refers to current view object.
On the other hand, if you need to only register JS files into a view, you may use:
$this->registerJsFile('path/to/file.js');
yii\web\View::registerJsFile()
And if you need to only register CSS files into a view, you may use:
$this->registerCssFile('path/to/file.css');
yii\web\View::registerCssFile()

You can remove the core jQuery from loading like so:
config/web.php
'assetManager' => [
'bundles' => [
// you can override AssetBundle configs here
'yii\web\JqueryAsset' => [
'sourcePath' => null,
'js' => []
],
],
],

Related

Custom configuration files in CakePHP 3

I have a CakePHP 3.3.14 application where I've created 2 subdirectories, webroot/data/downloads/ and webroot/data/master
I want to put these paths in a custom configuration file and reference them in a Controller. But I can't see how to do this.
I've followed the documentation on Configuration but it's not very clear.
So what I've done:
Created config/my_config.php
The above file defines an array:
return [ 'downloadsPath' => 'webroot/data/downloads/', 'masterPath' => 'webroot/data/master/' ];
In config/bootstrap.php I've put: Configure::load('my_config', 'default');
How do I then use this in a Controller? If I put Configure::read('my_config.masterPath'); it gives an error saying: Class 'App\Controller\Configure' not found
If I add use Cake\Core\Configure; to the top of my Controller, that clears the error but the return value is null:
debug(Configure::read('my_config.masterPath')); // null
Loading another config file just extends the default App.config. So just use \Cake\Core\Configure::read('masterPath') and you are good.
EDIT
If it is your goal to have different config paths you could do it like this:
// my_config.php
return [
'MyConfig' => [
'masterPath' => '...',
...
]
];
Then use the config like this:
<?= \Cake\Core\Configure::read('MyConfig.masterPath') ?>

Yii2: registerJs() implicitly includes JqueryAsset, how to avoid

In Yii2 there is a $this->registerJs() method available in views for registering inline JS. I use it as described in documentation:
$js = "...prepare js code...";
$this->registerJs($js, View::POS_READY);
The problem is that with View::POS_READY (which is the default for second argument) registerJs() implicitly requires yii\web\JqueryAsset (source code).
But I already included Jquery in my own asset bundle - it is all-min.js, there are Jquery + plugins minified and concatenated in a single file. Yii2 includes JqueryAsset, therefore duplicating Jquery on a resulting page.
How do I tell Yii2 that Jquery is already included or avoid this duplication in some other way?
You can easily customize jquery asset bundle by configuring assetManager in the application components configuration (usually config/web.php).
You can disable one or multiple asset bundles by associating false with the names of the asset bundles that you want to disable :
'assetManager' => [
'bundles' => [
'yii\web\JqueryAsset' => false,
],
],
Read more : http://www.yiiframework.com/doc-2.0/guide-structure-assets.html#customizing-asset-bundles

Where should I put a library in a Yii project that is not available via Composer?

I can't put the library under vendor/ because that directory is ignored in .gitignore. I put it under bing-ads/ and I have
<?php
namespace app\models;
include 'bing-ads\v10\bingads\ClientProxy.php';
use \Yii;
use BingAds\Proxy\ClientProxy;
to access it. It works for console commands/actions, but I have a feeling it will not work during a web call because the root directory will be web/. Where should I put this library and how can I access it via both console actions and web actions?
The Microsoft PHP library is located here.
I found a way by adding the file paths to the autoload section of composer.json. I remembered that I had to do that for some of the other libraries as well, even the ones available via Composer.
"autoload": {
"classmap": [
"vendor/googleads/googleads-php-lib/src/Google/Api/Ads/Common/Util",
"vendor/googleads/googleads-php-lib/src/Google/Api/Ads/AdWords/Util/v201605",
"bing-ads/v9/bingads/CustomerManagementClasses.php",
"bing-ads/v10/bingads/v10/CampaignManagementClasses.php",
"bing-ads/v10/bingads/v10/BulkClasses.php",
"bing-ads/v10/bingads/ClientProxy.php"
]
}
Then I ran
$ composer install
...
Generating autoload files
I'm not sure this is the best way though.
You could store them wherever you want e.g. in a folder named "BingAds".
Just add the alias as example in a common base config file /common/config/base.php which is included in your console as well as in your web application e.g. for your /web/index.php
$config = \yii\helpers\ArrayHelper::merge(
require(__DIR__ . '/../common/config/base.php'),
require(__DIR__ . '/../common/config/web.php'),
require(__DIR__ . '/../config/base.php'),
require(__DIR__ . '/../config/web.php')
);
Inside this common/config/base.php you could add your settings, extensions etc. which are valid for both the console and your web application
<?php
$config = [
...
'aliases' => [
'#BingAds' => '#app/BingAds/v10',
'#BingAds/Proxy' => '#app/BingAds/v10/bingads',
],
];
Your Clientproxy.php is stored as example in the directory /BingAds/Proxy/.
Then you don't have to include your files every time you want to use them and just write.
use BingAds\Proxy\ClientProxy;
I have unpacked your linked zip file and stored the files of the directory Bing Ads API in PHP\PHP\Bing Ads API in PHP to my application root directory BingAds whith the aliases mentioned above.
I have tested it by creating a clientProxy object in both a console and web application.
$test = new ClientProxy('test');
var_dump($test);
Both Printed out
object(BingAds\Proxy\ClientProxy)[140]
private 'authenticationToken' => null
private 'username' => null
private 'password' => null
private 'developerToken' => null
private 'wsdlUrl' => string 'test' (length=4)
private 'accountId' => null
private 'customerId' => null
private 'service' => null
private 'namespace' => null
I haven`t tested out other classes but I guess you get how it works.
Add this to your composer.json:
{
"repositories": [
{
"type": "package",
"package": {
"name": "microsoft/bing-ads",
"version": "9.0.0",
"dist": {
"url": "https://code.msdn.microsoft.com/Bing-Ads-API-Version-9-in-fb27761f/file/159208/2/Bing%20Ads%20API%20in%20PHP.zip",
"type": "zip"
},
"autoload": {
"classmap": [
"PHP/Bing Ads API in PHP/v10/bingads/"
]
}
}
}
],
"require": {
"microsoft/bing-ads": "9.0.0"
}
}
Then add composer generated autload.php file if you haven't already.
Then you can call the BingAds\Proxy\ClientProxy() without includes.
There's no better way:)
It's best to place external library to extensions directory.
And in config do
return [
'import' => [
'application.extensions.bing-ads.v10.bingads.ClientProxy',
],
...
];
in main and in console configs.
I usually just put the code in a components folder. If you're using the basic template, this folder can be under your application root; if you're using the advanced template, this folder can be under the necessary app: frontend, backend, console, or common. I recommend putting it under common for reasons I shall explain later
Under every app config, Yii 2 uses the ::setAlias method to assign different aliases to the key folders. In the basic app template, #app refers to the application root. While in the advanced template #app may refer to any of backend, frontend, or console.
If your library code is under backend, you can access it like so
namespace backend\controllers;
use yii\web\Controller;
use backend\components\MyLibCode;
class SiteController extends Controller
{
public function actionIndex()
{
$mlb = new MyLibCode();
// ...
}
}
However, it is good Yii 2 practice to have common library code in the common folder. So if this library code is to be used across apps, I suggest you put it into the common\components folder and replace backend with common in the use statement in the code above.
p.s: Justinas method also works; it's borrowed from Yii 1. But this may become cumbersome because this asks Yii to load the class when the application starts. If there is some heavy-lifting in that file, it may be detrimental to the app's performance.

How can we add minification in yii2 frontend application?

How to add minfication for css and js files or can i add minify them and add in single file .I have added some css and js file for full application and others are page wise?
AssetBundle represents a collection of asset files, such as CSS, JS, etc.
An asset bundle can depend on other asset bundles. When registering an asset bundle with a view, all its dependent asset bundles will be automatically registered.
please refer below link
Yii2 AssetBundle API DOC
AssetBundle Example
In Your Yii2 Basic Application
Yii2 Basic Application Asset Bundle Example
In Your Yii2 Advanced Application
First create one AppAsset AssetBundule in your frontend->assets->AppAsset.php.
<?php
namespace frontend\assets;
use yii\web\AssetBundle;
class AppAsset extends AssetBundle
{
public $basePath = '#webroot';
public $baseUrl = '#web';
public $css = [
....
css file here
....
];
public $js = [
....
js file here
....
];
public $jsOptions = [
....
js options here
....
];
public $depends = [
....
dependent asset bundles here
eg: 'yii\bootstrap\BootstrapAsset'
....
];
}
?>
Now register the AppAsset in your view file
<?php
use frontend\assets\AppAsset;
AppAsset::register($this);
?>
And Also Register Single js and css file
Single Js ans Css File Register
You can use https://github.com/skeeks-semenov/yii2-assets-auto-compress
It is easy and fast to configure. Once installed you only need to update your config file.
i.e
'components' => [
'assetsAutoCompress' => [
'class' => '\skeeks\yii2\assetsAuto\AssetsAutoCompressComponent',
],
and then bootstrap it.
'bootstrap' => ['log', 'assetsAutoCompress'],
That's it then you are ready to go.

ZF2 view plugin manager not merging config

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.

Categories