I had a project in Yii1.x and now I am using Yii2 for the same projects
Project hierarchy is something like this
Project1(yii1)/all yii files + project2(yii2)
project2(yii2)/frontend + /common + /backend
Now I want to know if is it possible to use project2/common/models in project1/protected/controllers
How can I achieve this task?
Thank you
I wouldn't recommend doing it, instead it's better to completely rewrite old application in Yii2.
But in case of partial migrating, please read this paragraph in Special Topics Section in Official Guide.
Here are some important code snippets from there:
1) Modification of entry script:
// include the customized Yii class described below
require(__DIR__ . '/../components/Yii.php');
// configuration for Yii 2 application
$yii2Config = require(__DIR__ . '/../config/yii2/web.php');
new yii\web\Application($yii2Config); // Do NOT call run()
// configuration for Yii 1 application
$yii1Config = require(__DIR__ . '/../config/yii1/main.php');
Yii::createWebApplication($yii1Config)->run();
2) Combination of Yii classes:
$yii2path = '/path/to/yii2';
require($yii2path . '/BaseYii.php'); // Yii 2.x
$yii1path = '/path/to/yii1';
require($yii1path . '/YiiBase.php'); // Yii 1.x
class Yii extends \yii\BaseYii
{
// copy-paste the code from YiiBase (1.x) here
}
Yii::$classMap = include($yii2path . '/classes.php');
// register Yii 2 autoloader via Yii 1
Yii::registerAutoloader(['Yii', 'autoload']);
// create the dependency injection container
Yii::$container = new yii\di\Container;
Usage of Yii class:
echo get_class(Yii::app()); // outputs 'CWebApplication'
echo get_class(Yii::$app); // outputs 'yii\web\Application'
Related
I have a custom module which installs a specific set of configurations - these are all stored in the config/install folder, which means they are installed when the module is installed.
The configuration includes a content type, paragraphs, view modes, form modes, field storages and fields attached to both the content type and the paragraphs, etc. The idea is to use this module to install a 'feature' (a blog) and use it across multiple sites, as well as provide updates and extensions when we add more stuff to this feature.
Since upon initial install, you cannot add more configuration through the config/install folder, I've been trying to find a way to import additional configuration files through an update hook, and this is one that works:
<?php
use \Symfony\Component\Yaml\Yaml;
/**
* Installs the file upload element
*/
function MODULE_NAME_update_8002() {
// Is the flaw with this the fact that the order of loading configurations now
// matters and is a little bit more difficult to deal with?
// NOTE: YES. If, for example, you comment out the installing of the
// field_storage for the field_cb_file, but try to add the field_cb_file to
// the paragraph type, the update is successful and no errors are thrown.
// This is basically me trying to re-create the drupal configuration management
// system, without the dependency checks, etc. What is the PROPER way of
// importing additional configuration from a module through an update?
// FIXME:
$configs_to_install = [
'paragraphs.paragraphs_type.cbsf_file_download',
'field.storage.paragraph.field_cb_file',
'field.field.paragraph.cbsf_file_download.field_cb_file',
'field.field.paragraph.cbsf_file_download.field_cb_heading',
'field.field.paragraph.cbsf_file_download.field_cb_icon',
'field.field.paragraph.cbsf_file_download.field_cb_text',
'core.entity_form_display.paragraph.cbsf_file_download.default',
'core.entity_view_display.paragraph.cbsf_file_download.default',
];
foreach ($configs_to_install as $config_to_install) {
$path = drupal_get_path('module', 'MODULE_NAME') . '/config/update_8002/' . $config_to_install . '.yml';
$content = file_get_contents($path);
$parsed_yml = Yaml::parse($content);
$active_storage = \Drupal::service('config.storage');
$active_storage->write($config_to_install, $parsed_yml);
}
}
however, there are flaws with this method since it means you have to order configuration files in the right order if they depend on each other, and any dependencies that are present in the config file are not checked.
Is there a way to utilise configuration management to import config properly, in this same, 'loop over the files' way? Or to point to a folder that contains all of the config files and install them?
EDIT: There are further issues with this method - even if you've ordered the files correctly in terms of dependencies, no database tables are created. The configuration is simply 'written in' as is, and no other part of Drupal seems to be made aware that new entities were created, so they cannot run any of the functions that are otherwise ran if you were to create the entities through Drupal GUI. Definitely not the recommended way of transferring more complex configuration.
I've pushed this a step further - there is a way to use the EntityTypeManager class to create / update configurations.
2 links have helped me with this largely:
https://drupal.stackexchange.com/questions/164713/how-do-i-update-the-configuration-of-a-module
pwolanins answer at the bottom provides a function that either updates the configuration if it exists, or creates the configuration outright.
https://www.metaltoad.com/blog/programmatically-importing-drupal-8-field-configurations
the code on this page gives a clearer idea of what is happening - for each configuration that you'd like to install, you run the YML file through the respective storage manager, and then create the appropriate entity configurations, which creates all of the required DB tables.
What I ended up doing was:
Utilised a slightly modified version of pwolanins code and create a generic config updater function -
function _update_or_install_config( String $prefix, String $update_id, String $module) {
$updated = [];
$created = [];
/** #var \Drupal\Core\Config\ConfigManagerInterface $config_manager */
$config_manager = \Drupal::service('config.manager');
$files = glob(drupal_get_path('module', $module) . '/config/update_' . $update_id. '/' . $prefix . '*.yml') ;
foreach ($files as $file) {
$raw = file_get_contents($file);
$value = \Drupal\Component\Serialization\Yaml::decode($raw);
if(!is_array($value)) {
throw new \RuntimeException(sprintf('Invalid YAML file %s'), $file);
}
$type = $config_manager->getEntityTypeIdByName(basename($file));
$entity_manager = $config_manager->getEntityManager();
$definition = $entity_manager->getDefinition($type);
$id_key = $definition->getKey('id');
$id = $value[$id_key];
/** #var \Drupal\Core\Config\Entity\ConfigEntityStorage $entity_storage */
$entity_storage = $entity_manager->getStorage($type);
$entity = $entity_storage->load($id);
if ($entity) {
$entity = $entity_storage->updateFromStorageRecord($entity, $value);
$entity->save();
$updated[] = $id;
}
else {
$entity = $entity_storage->createFromStorageRecord($value);
$entity->save();
$created[] = $id;
}
}
return [
'udpated' => $updated,
'created' => $created,
];
}
I placed all of my yml files in folder config/update_8002, then utilised this function to loop over the config files in a hook_update_N function:
function MODULE_NAME_update_8002() {
$configs_to_install = [
'paragraphs.paragraphs_type.cbsf_file_download',
'core.entity_form_display.paragraph.cbsf_file_download.default',
'core.entity_view_display.paragraph.cbsf_file_download.default',
'field.storage.paragraph.field_cb_file',
'field.field.paragraph.cbsf_file_download.field_cb_file',
'field.field.paragraph.cbsf_file_download.field_cb_heading',
'field.field.paragraph.cbsf_file_download.field_cb_icon',
'field.field.paragraph.cbsf_file_download.field_cb_text',
];
foreach ($configs_to_install as $config_to_install) {
_update_or_install_config('paragraphs.paragraphs_type', '8002', 'MODULE_NAME');
_update_or_install_config('field.storage.paragraph', '8002', 'MODULE_NAME');
_update_or_install_config('field.field.paragraph', '8002', 'MODULE_NAME');
_update_or_install_config('core.entity_view_display.paragraph', '8002', 'MODULE_NAME');
_update_or_install_config('core.entity_form_display.paragraph', '8002', 'MODULE_NAME');
}
}
Note that the _update_or_install_config function loops over all of the configs in the folder that match a specific entity type manager - thus you should just include the prefix in the function, and all of the YML files that import configuration of the same type will be included.
I have google lib - https://github.com/rapidwebltd/php-google-contacts-v3-api
and i need to implement it in YII framework
How, for example implement this code in YII:
require_once '../../../vendor/autoload.php';
use rapidweb\googlecontacts\helpers\GoogleHelper;
$client = GoogleHelper::getClient();
$authUrl = GoogleHelper::getAuthUrl($client);
How to use namespaces in my case ?
In order to use the composer autoloader, you have to unregister the Yii one first.
Example:
spl_autoload_unregister(array('YiiBase','autoload'));
require '../../../vendor/autoload.php';
spl_autoload_register(array('YiiBase','autoload'));
$client = rapidweb\googlecontacts\helpers\GoogleHelper::getClient();
$authUrl = rapidweb\googlecontacts\helpers\GoogleHelper::getAuthUrl($client);
I have a custom authentication service and in ZF2 I accessed this as follows:
Application/view/layout/layout.phtml
$authenticationService = $this->getHelperPluginManager()
->getServiceLocator()
->get('AuthenticationService');
$currentIdentity = $authenticationService->getIdentity();
Now the Zend\ServiceManager#getServiceLocator() is deprecated.
How to get a service available in a view script (or concrete in this case in the layout) in ZF3?
For this purpose there is already Identity View Helper
As documentation says
// Use it any .phtml file
// return user array you set in AuthenticationService or null
$user = $this->identity();
The solution is to assign a global view variable in the onBootstrap(...):
namespace Application;
use ...
class Module
{
public function onBootstrap(MvcEvent $e)
{
...
$serviceManager = $e->getApplication()->getServiceManager();
$viewModel = $e->getApplication()->getMvcEvent()->getViewModel();
$viewModel->authenticationService = $serviceManager->get('AuthenticationService');
}
...
}
Another (perhaps an even better/cleaner) solution is to use a ViewHelper. See also here.
I am using SuiteCRM ( Sugar CRM 6.x community edition ) & want to create a custom login page and after successful login I want to redirect based on user type
tried to create some modules but there is no clear documentation except few of useful links, below are my queries :
Can we create custom modules without using module builder, if yes then what would be steps?
Do we need to write module in /module folder or /custom/module folder or on both place?
any link is also appreciated.
You can create a custom Login Page by modfying "modules/Users/login.tpl"
Custom Modules can be created through Modulebuilder or manually.
When creating modules manually it's important to use the right names.
The easiest way is a Plural name for the folder, table and Module and a singular name for the class.
Manual steps:
You need a Folder in modules/ named like you module (i.e. CAccounts)
In this folder you need a file named like the class (i.e CAccount.php) with something like that as content:
require_once('data/SugarBean.php');
require_once('include/utils.php');
class CAccount extends SugarBean{
var $table_name = 'caccounts';
var $object_name = 'CAccount';
var $module_dir = 'CAccounts';
var $new_schema = true;
var $name;
var $created_by;
var $id;
var $deleted;
var $date_entered;
var $date_modified;
var $modified_user_id;
var $modified_by_name;
function CAccount (){
parent::SugarBean();
}
function get_summary_text(){
return $this->name;
}
function bean_implements($interface)
{
switch($interface)
{
case 'ACL':return true;
}
return false;
}
}
In this folder you need a vardefs.php file:
$dictionary['CAccount'] = array(
'table'=>'caccounts',
'audited'=>false,
'fields'=>array (
//Your fielddefs here
)
);
require_once('include/SugarObjects/VardefManager.php');
VardefManager::createVardef('CAccounts','CAccount', array('basic'));
For the language and metadata folders look at any other module.
Next is a file at "custom/Extension/application/Ext/Include/CAccounts.include.php"
$moduleList[] = 'CAccounts';
$beanList['CAccounts'] = 'CAccount';
$beanFiles['CAccount'] = 'modules/CAccounts/CAccount.php';
A language file for the module name must be in "custom/Extension/application/Ext/Language/"
$app_list_strings['moduleList']['CAccounts'] = 'Custom Accounts';
To display the Module in your tabs you need to use "rebuild and repair" and then the "Display Modules and Subpanels" option in the admin menu.
For a custom module you don't need the "custom/" folder structure. Files there will be used by sugar if provided, but often there's no need for that in a custom module.
Guides about the Module Framework can be found on the sugarcrm support site:
http://support.sugarcrm.com/02_Documentation/04_Sugar_Developer/Sugar_Developer_Guide_6.5/03_Module_Framework
I have a login button in the header of the website. This header's html is programmed into Zend framework views/layouts/home.phtml.
I have a hidden form in this layout that is triggered by jQuery thickbox inline content display integration. Reason, I dont want to make a ajax call to just fetch a small login form.
I create the form using Zend_Form and the problem is that I have to do it in all the controllers after checking if the user is logged in or not. I want to place this form generation in one single place, say in bootstrap and then have a logic in bootstrap to say that if user is logged in dont generate the form.
I don't know if bootstrap is the right place to do so or should I do it in some other place.
So, where should I instantiate the form so that its available everywhere if user is not logged in.
Create your own base controller which extends Zend_Controller_Action then have your controllers extend off of your base controller. I don't know what "jQuery thickbox inline content display integration" is...but you have several sections you can put it in depending when you need your code to run. init(), preDispatch(), postDispatch() etc... Just make sure when you extend off your base controller that you do sthing like:
parent::init()
parent::preDispatch()
parent::postDispatch()
etc... within each section so that the base code runs as well...
Be careful about Pradeep Sharma's solution (the answer he wrote himself and accepted below).
All the code code below is for ZF 1.12, and not ZF 2.0
In the bootstrap, Zend_Layout's MVC instance might not have been created yet. You should use Zend_Layout::startMvc() instead :
$view = Zend_Layout::startMvc()->getView() ;
And tbh I prefer executing this code in the preDispatch() function. New users of ZF might be interested in this :
application/plugins/HeaderForm.php :
class Application_Plugin_HeaderForm extends Zend_Controller_Plugin_Abstract
{
public function preDispatch(Zend_Controller_Request_Abstract $request)
{
$view = Zend_Layout::startMvc()->getView() ;
$view->headerForm = new Application_Form_HeaderForm() ;
}
}
Calling new Application_Form_HeaderForm() will autoload by default into application/forms/ folder. You can also create the form directly into the plugin with new Zend_Form(), and addElement() etc. but it won't be reusable.
Of course, you need to register this plugin in your bootstrap!
application/Bootstrap.php :
class Bootstrap extends Zend_Application_Bootstrap_Bootstrap
{
protected function _initPlugin()
{
$front = Zend_Controller_Front::getInstance() ;
$front->registerPlugin(new Application_Plugin_HeaderForm()) ;
}
}
Calling new Application_Plugin_HeaderForm() will autoload by default into application/plugins/ folder
I did it in a different way, extendingZend_Controller_Plugin_Abstract to implement a plugin and register it with front controller.
public function routeStartup(Zend_Controller_Request_Abstract $request) { }
generated the form inside the above mentioned method and by setting the form in $view object.
$view can be retrived using :
$view = Zend_Layout :: getMvcInstance()->getView();