CakePHP change locale dynamically - cakephp

I've my CakePHP app internationalized through .po files.
The file structure is as follows:
- src
- Locale
- en_EN
- en_ES
The app is correctly translated at startup by:
ini_set('intl.default_locale', 'en_ES');
But, I need the app to be translated dynamically, in an action listener button for example.
I tried the following, but it doesn't work:
use Cake\I18n\I18n;
I18n::locale('en_EN');

You need to save the locale in the session so that it persists between page requests.
A possible approach:
class AppController extends Controller {
public function initialize() {
if ($this->request->session()->check('Config.locale')) {
I18n::locale($this->request->session()->read('Config.locale'));
}
//rest of your init code
}
public function change_locale($locale){
$this->request->session()->write('Config.locale', $locale);
return $this->redirect($this->referer());
}
}

Related

How to get this code work to store in Laravel. No errors and no storage

I can't store name and IP address to DB. I created a table 'info' with appropriate fields by running php artisan migrate.
A schema
Schema::create('info', function (Blueprint $table) {
$table->increments('id');
$table->string('name');
$table->string('ip');
$table->timestamp('created_at')->nullable();
});
A model for Info
class Info extends Model
{
protected $fillable = ['ip', 'name'];
}
Maybe the problem is in my HomeController where I get those variables?
<?php
namespace App\Http\Controllers;
use Illuminate\Foundation\Auth\User as Authenticatable;
use App\Info;
use App\Http\Controllers\Controller;
use Illuminate\Support\Facades\Auth;
use Request;
class HomeController extends Controller
{
public function __construct()
{
$this->middleware('auth');
}
public function store(Request $request) {
Info::create(['info' => $request->input('info')]);
}
public function index()
{
if (Auth::check())
{
$name = Auth::user()->name;
$ip = Request::ip();
\App\Events\eventIp::dispatch($ip,$name);
return view('home');
}
}
}
My routes in web.php
Route::post('/home','HomeController#store');
Route::get('/home', 'HomeController#index')->name('home');
});
But it doesn't work. Gives no errors and no records in DB.
Something make me think that it have to do with my index function. I got info in function index and maybe function store doesn't have a clue what I mean.
A controller action is basically a method that usually gets executed when you open an url (as you connect them to routes).
In your example you have connected two routes to their respective actions:
Route::post('/home','HomeController#store');
Route::get('/home', 'HomeController#index')->name('home');
Now, when you log in succesfully, imagine that you end up in the page with url http://localhost:8000/home in your web browser.
The key difference is the method which you use to call your route (you can get an overview of the differences here), in your case you are using GET method.
The resulting action executed it the one associated to /home route with the GET method, that is the HomeController#index action (or method).
The store method, although is in the same HomeController class, doesn't get triggered unless you execute the /home route, but with the POST method.
You can confirm that if you put a debug message in each of the methods like this:
class HomeController extends Controller
{
public function __construct()
{
$this->middleware('auth');
}
public function store(Request $request)
{
echo 'I will not be executed';
}
public function index()
{
echo 'I have been executed';
}
}
If you want to simply save a info record when you visit the /home route with the GET method, you can put the save in the index method itself and get rid of the store method:
class HomeController extends Controller
{
public function __construct()
{
$this->middleware('auth');
}
public function index()
{
// You can omit Auth::check() because you are using the auth middleware
// that exactly does this job.
Info::create([
'name' => Auth::user()->name,
'ip' => Request::ip(),
]);
return view('home');
}
}
Keep in mind that doing in this way you will get a new database record for each page view you make to that route (if you keep refreshing the page, you should see new records being added to database).
Update
When you use Eloquent Models, laravel will look for a table named after the pluralized model name (Info model will try to use infos table).
However you created a table named info. To solve that you can either rename the table and rerun the migration with php artisan migrate:refresh (it will delete all the existing data in the database you are using for your laravel app)
Or specify the table name to use for that laravel model:
class Info extends Model
{
protected $table = 'info';
protected $fillable = ['ip', 'name'];
}
How are you calling the functions? There is a couple of things wrong with your code, but you're saying there are no errors at all.
Firstly, your Info::create call does not need the ['info' => $request->input('info')] info. This is because your Info model has no database property called info, but normally you would get an obvious error with the approach, which is why I expect you are also calling the store method incorrectly.
Call the create method like so:
$infoModel = Info::create(['name' => $request->input('name'), 'ip' => $request->input['ip']]);
or, if you can guarantee your $request only contains the needed fields (properly validated), you can just do
$infoModel = Info::create($request->all());
Add a little more info to the question on how you are calling store and we can probably solve the rest of your problem.
Within your store function inside HomeController , use
Info::create([
'name' => Auth::user()->name,
'ip' => Request::ip(),
]);
and make sure Info model is imported.
Also make sure your route has the call to store function while POSTing data .

Force CakePHP plugin to use its own layout

I have written a CakePHP plugin https://github.com/anuj9196/CakePHP-App-Installer
The plugin is using default.ctp layout from plugin_path/src/template/layout/default.ctp
When there is some other theme used in the host application. Like in my case I have setup one in AppController's beforeRender()
$this->viewBuilder()->setTheme('DashboardTemplate');
DashboardTemplate is in application's /plugin/ directory.
Now, when I access my plugin's URL using example.com/installer/install
The template loads on top of DashboardTemplate theme.
How can I disable them in plugin's AppController?
The AppController inside plugin directory contains
<?php
namespace Installer\Controller;
use App\Controller\AppController as BaseController;
class AppController extends BaseController
{
// nothing here
}
Remove the theme by using beforeRender() in your plugin's AppController.
<?php
namespace Installer\Controller;
use App\Controller\AppController as BaseController;
class AppController extends BaseController
{
/**
* #param \Cake\Event\Event $event The beforeRender event.
* #return \Cake\Http\Response|null|void
*/
public function beforeRender(Event $event)
{
try {
return parent::beforeRender($event);
} finally {
$this->viewBuilder()->setTheme(null);
}
}
}
You can switch between layouts in your view and controllers fairly easily.. using plugin syntax
// inside controller
$this ->layout = 'Plugin.layout';
//inside view template
$this ->layout = 'Plugin.layout';
If you just want to disable the theme, use Mathew's method above. But be careful that will disable the theme for the whole application not just this plugin in case some of your app code is ran after your plugin

Cakephp plugin layout is applying to all pages

I am facing a strange error in cakephp2.0. I have created two layouts - one for plugin and one for front end users. Whenever I take the front end and after that if I take the plugin in the url, the front end layout is getting applied to all pages coming under plugin and vice verse. After 8-10 refresh it will take the correct layout. How to avoid caching of layout variable in this case ?
VideosController under app/Controller folder
App::uses('AppController', 'Controller');
class VideosController extends AppController
{
public function index()
{
$this->layout = 'default';
$this->set('videos', $this->Video->find('list'));
}
}
My plugin Main controller
class AdminAppController extends AppController
{
var $layout = 'admin';
}
Another controller inside my plugin
App::uses('AdminAppController', 'Admin.Controller');
class VideosController extends AdminAppController
{
public function index()
{
$this->Video->recursive = 0;
$this->set('videos', $this->paginate());
}
}
You can set parts of your view to not be cached, or you could clear the cache every time the layout is changed. Check: http://book.cakephp.org/2.0/en/core-libraries/helpers/cache.html

Why CakePHP 2.0 is not using my AppController?

I have just upgraded to Cakephp 2.0 alpha, and immediately faced a problem. The app_controller.php in the app/ folder is not loaded in my controllers. Instead controllers use the CakePHP own AppController.php in the lib/Cake/Controller/AppController.php.
I have tried renaming the app_controller to AppController.php aswell but its not working. I have tried deleting the whole file and then copying the lib/Cake/Controller/AppController.php file and then editing it but not working.
I have also tried deleting cache files.
I just simply use:
class AppController extends Controller {
public function beforeFilter() {
die;
}
}
And the application wont die.
My controller is also simply just:
class NewsController extends AppController {
function beforeFilter() {
parent::beforeFilter();
}
function index() {
}
}
So what I could be doing wrong? Im also using Windows 7 + Netbeans with Subversion to update project (if that has anything to do with it :p).
Did much of searching and didn't look from most obvious place: Github cakephp docs: https://github.com/cakephp/docs/blob/master/en/controllers.rst . I thought they were still 1.3 docs but it appears they are updated. Since they are now updated, it says that I should put the old app_controller.php into Controller folder and camel case it to AppController.php.
Create file AppController.php in app/Controller directory
class AppController extends Controller {
public $helpers = array('Html', 'Form', 'Javascript');
public function beforeFilter() {
die('app/Controller/AppController.php file called');
parent::beforeFilter();
}
}

Override model validate errors

I am new to CakePHP.
I would like to use the model validate mechanism, but I'm having trouble overriding the errors that are displayed. I am building an API where all the views need to be rendered in JSON and I have a JSON format that all errors need to output as. I've defined a custom AppError class and I have successfully be able to define custom errors in this format there.
Is there a way to use the AppError class to override the output of the error messages coming from validation?
Thanks.
I came up with a solution by adding these methods to my AppModel class:
function validates($options = array()) {
$result = parent::validates($options);
if (!$result) {
$this->_validateErrors();
}
return $result;
}
function _validateErrors() {
foreach ($this->validationErrors as $code) {
$this->cakeError('apiError', array('code' => $code)); // Custom JSON error.
return;
}
}
I then manually call $this->Model->validates() before a Model::save() call in my controller. This seems to be working well.
As far as I know, there's no direct way to get validation errors from within your AppError class. The way around it would be to create an AppModel class in app/app_model.php and use the onError() callback method to pass the error to your AppError class.
// app/app_model.php
class AppModel extends Model {
public function onError() {
// Pass the errors to your AppError class
AppError::someErrorMethod($this->getErrors());
}
}

Resources