In a ZF2 modular application, I have 2 differents view helpers with the same name in 2 differents modules.
I want to use one in the first module, and the other one in the second module.
In the first module configuration file, I have a view_helpers config key with my view helpers definitions.
view_helpers => [
myCustomViewHelper => myCustomViewHelper::class
]
In the second one, I have a my_module_view_helpers config key ...
my_module_view_helpers => [
myCustomViewHelper => myCustomViewHelper2::class
]
What I want to do, is to erase the first one by the second one for the second module.
How is it possible to achieve that ?
I understood that Module load order determines which gets actually registered. If you load your custom module last, it should become the defacto helper with that name.
Make sure to use the right keys in both module configs.
'view_helpers' => [
'invokables' => [
'thatHelper' => ThatHelper::class,
],
'factories' => [
'otherHelper' => ThatOtherHelper::class,
]
]
What you'll run into though, is any program reference to that helper in 'other' modules will also use yours. Unless that's the intention, that could cause a world of hurt. My advice, give it a new name. ;) It's just a name! :D
Related
I'm building ZF3 based application with my own library that contains base components to include in other projects. Library is composer based so the application tree looks like this:
- module
-- Application
--- src
---- view
----- index.phtml (where I want to include partial from base)
- vendor
-- myBaseScripts (installed via composer)
--- partials
---- myTablePartial.phtml (partial to include)
Can I include partial that is not inside of module/Application/view but inside vendor/myBaseScripts/partials?
Sure. However, you're hereby advised to make sure that the module you're creating contains a default view.
To register a view partial, use the config of a module, like so:
'view_manager' => [
'template_map' => [
'name/of/partial/view' => __DIR__ . '/../path/relative/to/config/file/view-partial.phtml',
],
],
Make sure that your module contains something like the above.
You then use this in a view like so:
<?= $this->partial('name/of/partial/view', ['param1' => 'value1']) ?>
$this->partial is a ViewHelper. The first argument it takes is which partial to load (by name!). The second parameter is an optional array, which contains key/value pairs for data.
To overwrite a partial, such as a default module partial, with a custom one in another module, you must overwrite the value of the key/value pair in the config.
This module, with the modified partial, must be loaded after the 'original' one. This is to ensure that the config gets overwritten in the order you're expecting.
Assuming the code above is in your original module, you would do the below in another module:
'view_manager' => [
'template_map' => [
'name/of/partial/view' => __DIR__ . '/../path/relative/to/config/file/this-is-a-custom-partial.phtml',
],
],
As you can see, the name is still the same.
Happy coding.
I am using the Yii2 Framework and I am translating all texts of buttons, labels, messages, etc.
Then I read this article http://www.yiiframework.com/doc-2.0/guide-tutorial-i18n.html that shows how to do it automatically but I don't understand it.
I want to translate to Spanish from Argentina: es-AR or at least to any Spanish.
So I think I need to change from en-US to es-AR but I would like to know which files should I change.
Also I am using the great Gii code generator where I can see a checkbox called Enable I18N.
I watched these files but I am not sure if I am looking the right files:
vendor/yiisoft/yii2/base/Application.php
vendor/yiisoft/yii2/i18n/I18N.php
common/config/main-local.php
Add language propery and i18n component in application config. For advanced application template in common/config/main.php
return [
'language' => 'es-AR',
...
'components' => [
...
'i18n' => [
'translations' => [
'app*' => [
'class' => 'yii\i18n\PhpMessageSource',
'basePath' => '#app/messages',
],
],
],
...
],
]
Use Yii::t() for all user messages (model labels, views, error messages etc).
echo \Yii::t('app', 'Friend');
Create directory messages/es-AR. Create file app.php in this directory and add translations
return [
'Friend' => 'Amigo',
'Girl' => 'Сhica',
...
];
Try to look into the official documentation, it is best tutorial for you. http://www.yiiframework.com/doc-2.0/guide-tutorial-i18n.html
Also, look at this answer yii2 basic multiple language
You can change default language by changing 'language' parameter of your main configuration file. Like this:
return
[
// set target language to be English
'language' => 'en-US',
]
Where instead 'en-US' you must to set needed locale code, e.g. 'es-AR'
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.
How to enable multitranslation in yii 2 basic framework? I have tried, but it is not working. I get no error, but translation is not showing. Code:
public function actionLang(){
$lang = \Yii::$app->request->get('lang');
if($lang && in_array($lang,['en-US','ar-SA'])){
$cookie = new Cookie();
$cookie->name = '_lang';
$cookie->value = $lang;
$cookie->expire = time() + 60 * 60 * 24 * 180;
\Yii::$app->response->cookies->add($cookie);
}
$this->redirect(['index']);
}
I'm using this function in SiteController.
Internationalization in Yii is not a one-action job. Here's the documentation on how to make your website multilingual:
https://github.com/yiisoft/yii2/blob/master/docs/guide/tutorial-i18n.md
If docs are unclear, here is a tutorial:
http://code.tutsplus.com/tutorials/programming-with-yii2-localization-with-i18n--cms-23140
If you have gone through all the steps and merely wish to set the current language, you can use:
\Yii::$app->language = 'xxx';
where xxx is a language code in accordance with ISO 639-2.
Here are the mentioned standard's entries:
http://www.loc.gov/standards/iso639-2/php/code_list.php
First of all, from what I have gathered, you are trying to identify a language requested from the current request by doing $lang = \Yii::$app->request->get('lang'); and then set it in the cookie. In my opinion, this should be used as a "helper", meaning, it is useful to know the language preference of the returning client, but you still have to manage languages via URL, i.e. http://yoursite.com/en or http://yoursite.com/de should serve different languages.
Now, there are actually very good plugins out there for multilingual URL management, such as yii2-localeurls , which you can find here. I use it in production in multiple projects and highly recommend it.
To actually manage translations, you have to have a folder in the root of your project (if you are using advance template, you should have it inside frontend/backend/console ) to store the actual block translations, call it messages .
Now, under #app/messages create folders for each non-default language, for example #app/messages/de for German translations.
If you go your config in #app/config/main.php, look for i18n key inside the components array. If you can't find such a key, simply put the following into the components array:
'i18n' => [
'translations' => [
'app*' => [
'class' => 'yii\i18n\PhpMessageSource',
'basePath' => '#app/messages',
'sourceLanguage' => 'en',
'fileMap' => [
'app' => 'app.php',
'app/error' => 'error.php',
],
],
'*' => [
'class' => 'yii\i18n\PhpMessageSource',
]
],
],
Now, you will need to create a translation file inside the relevant directory. In the above configuration, we declared that the default language used is en, that means that all original messages would be in English. Go to #app/messages/de and create a translations file inside that directory. You can call it whatever you like, but for this example, call it site.php.
In this site.php put the following:
return [
'Translate this!' => 'Your relevant translation here in whichever language',
'Translate this also!!!' => 'Stuff...'
];
If all done correctly, when you access your page via http://yousite.com/de, when using Yii::t('site', 'Translate this!') you should be getting 'Your relevant translation here in whichever language' instead.
The beauty of Yii 2 is that it is extremely well documented. Visit the official documentation if you are stuck, it really explains everything quite well.
So I'm writing a framework on which I want to base a few apps that I'm working on (the framework is there so I have an environment to work with, and a system that will let me, for example, use a single sign-on)
I want to make this framework, and the apps it has use a Resource Oriented Architecture.
Now, I want to create a URL routing class that is expandable by APP writers (and possibly also by CMS App users, but that's WAYYYY ahead in the future) and I'm trying to figure out the best way to do it by looking at how other apps do it.
I prefer to use reg ex over making my own format since it is common knowledge. I wrote a small class that I use which allows me to nest these reg ex routing tables. I use to use something similar that was implemented by inheritance but it didn't need inheritance so I rewrote it.
I do a reg ex on a key and map to my own control string. Take the below example. I visit /api/related/joe and my router class creates a new object ApiController and calls it's method relatedDocuments(array('tags' => 'joe'));
// the 12 strips the subdirectory my app is running in
$index = urldecode(substr($_SERVER["REQUEST_URI"], 12));
Route::process($index, array(
"#^api/related/(.*)$#Di" => "ApiController/relatedDocuments/tags",
"#^thread/(.*)/post$#Di" => "ThreadController/post/title",
"#^thread/(.*)/reply$#Di" => "ThreadController/reply/title",
"#^thread/(.*)$#Di" => "ThreadController/thread/title",
"#^ajax/tag/(.*)/(.*)$#Di" => "TagController/add/id/tags",
"#^ajax/reply/(.*)/post$#Di"=> "ThreadController/ajaxPost/id",
"#^ajax/reply/(.*)$#Di" => "ArticleController/newReply/id",
"#^ajax/toggle/(.*)$#Di" => "ApiController/toggle/toggle",
"#^$#Di" => "HomeController",
));
In order to keep errors down and simplicity up you can subdivide your table. This way you can put the routing table into the class that it controls. Taking the above example you can combine the three thread calls into a single one.
Route::process($index, array(
"#^api/related/(.*)$#Di" => "ApiController/relatedDocuments/tags",
"#^thread/(.*)$#Di" => "ThreadController/route/uri",
"#^ajax/tag/(.*)/(.*)$#Di" => "TagController/add/id/tags",
"#^ajax/reply/(.*)/post$#Di"=> "ThreadController/ajaxPost/id",
"#^ajax/reply/(.*)$#Di" => "ArticleController/newReply/id",
"#^ajax/toggle/(.*)$#Di" => "ApiController/toggle/toggle",
"#^$#Di" => "HomeController",
));
Then you define ThreadController::route to be like this.
function route($args) {
Route::process($args['uri'], array(
"#^(.*)/post$#Di" => "ThreadController/post/title",
"#^(.*)/reply$#Di" => "ThreadController/reply/title",
"#^(.*)$#Di" => "ThreadController/thread/title",
));
}
Also you can define whatever defaults you want for your routing string on the right. Just don't forget to document them or you will confuse people. I'm currently calling index if you don't include a function name on the right. Here is my current code. You may want to change it to handle errors how you like and or default actions.
Yet another framework? -- anyway...
The trick is with routing is to pass it all over to your routing controller.
You'd probably want to use something similar to what I've documented here:
http://www.hm2k.com/posts/friendly-urls
The second solution allows you to use URLs similar to Zend Framework.
Use a list of Regexs to match which object I should be using
For example
^/users/[\w-]+/bookmarks/(.+)/$
^/users/[\w-]+/bookmarks/$
^/users/[\w-]+/$
Pros: Nice and simple, lets me define routes directly
Cons: Would have to be ordered, not making it easy to add new things in (very error prone)
This is, afaik, how Django does it
I think a lot of frameworks use a combination of Apache's mod_rewrite and a front controller. With mod_rewrite, you can turn a URL like this: /people/get/3 into this:
index.php?controller=people&method=get&id=3. Index.php would implement your front controller which routes the page request based on the parameters given.
As you might expect, there are a lot of ways to do it.
For example, in Slim Framework , an example of the routing engine may be the folllowing (based on the pattern ${OBJECT}->${REQUEST METHOD}(${PATTERM}, ${CALLBACK}) ):
$app->get("/Home", function() {
print('Welcome to the home page');
}
$app->get('/Profile/:memberName', function($memberName) {
print( 'I\'m viewing ' . $memberName . '\'s profile.' );
}
$app->post('/ContactUs', function() {
print( 'This action will be fired only if a POST request will occure');
}
So, the initialized instance ($app) gets a method per request method (e.g. get, post, put, delete etc.) and gets a route as the first parameter and callback as the second.
The route can get tokens - which is "variable" that will change at runtime based on some data (such as member name, article id, organization location name or whatever - you know, just like in every routing controller).
Personally, I do like this way but I don't think it will be flexible enough for an advanced framework.
Since I'm working currently with ZF and Yii, I do have an example of a router I've created as part of a framework to a company I'm working for:
The route engine is based on regex (similar to #gradbot's one) but got a two-way conversation, so if a client of yours can't run mod_rewrite (in Apache) or add rewrite rules on his or her server, he or she can still use the traditional URLs with query string.
The file contains an array, each of it, each item is similar to this example:
$_FURLTEMPLATES['login'] = array(
'i' => array( // Input - how the router parse an incomming path into query string params
'pattern' => '#Members/Login/?#i',
'matches' => array( 'Application' => 'Members', 'Module' => 'Login' ),
),
'o' => array( // Output - how the router parse a query string into a route
'#Application=Members(&|&)Module=Login/?#' => 'Members/Login/'
)
);
You can also use more complex combinations, such as:
$_FURLTEMPLATES['article'] = array(
'i' => array(
'pattern' => '#CMS/Articles/([\d]+)/?#i',
'matches' => array( 'Application' => "CMS",
'Module' => 'Articles',
'Sector' => 'showArticle',
'ArticleID' => '$1' ),
),
'o' => array(
'#Application=CMS(&|&)Module=Articles(&|&)Sector=showArticle(&|&)ArticleID=([\d]+)#' => 'CMS/Articles/$4'
)
);
The bottom line, as I think, is that the possibilities are endless, it just depend on how complex you wish your framework to be and what you wish to do with it.
If it is, for example, just intended to be a web service or simple website wrapper - just go with Slim framework's style of writing - very easy and good-looking code.
However, if you wish to develop complex sites using it, I think regex is the solution.
Good luck! :)
You should check out Pux https://github.com/c9s/Pux
Here is the synopsis
<?php
require 'vendor/autoload.php'; // use PCRE patterns you need Pux\PatternCompiler class.
use Pux\Executor;
class ProductController {
public function listAction() {
return 'product list';
}
public function itemAction($id) {
return "product $id";
}
}
$mux = new Pux\Mux;
$mux->any('/product', ['ProductController','listAction']);
$mux->get('/product/:id', ['ProductController','itemAction'] , [
'require' => [ 'id' => '\d+', ],
'default' => [ 'id' => '1', ]
]);
$mux->post('/product/:id', ['ProductController','updateAction'] , [
'require' => [ 'id' => '\d+', ],
'default' => [ 'id' => '1', ]
]);
$mux->delete('/product/:id', ['ProductController','deleteAction'] , [
'require' => [ 'id' => '\d+', ],
'default' => [ 'id' => '1', ]
]);
$route = $mux->dispatch('/product/1');
Executor::execute($route);
Zend's MVC framework by default uses a structure like
/router/controller/action/key1/value1/key2/value2
where router is the router file (mapped via mod_rewrite, controller is from a controller action handler which is defined by a class that derives from Zend_Controller_Action and action references a method in the controller, named actionAction. The key/value pairs can go in any order and are available to the action method as an associative array.
I've used something similar in the past in my own code, and so far it's worked fairly well.
Try taking look at MVC pattern.
Zend Framework uses it for example, but also CakePHP, CodeIgniter, ...
Me personally don't like the MVC model, but it's most of the time implemented as "View for web" component.
The decision pretty much depends on preference...