Our site is multilanguage (for a client). But instead of translate words like "login" in the PO files, we need to extract them from our translations table in the database. This is a client requirement.
I did research in which way I could make a function that is accessible from anywhere (view, controller, etc.). I concluded that the best way was to make a custom Library, because it said it could be used anywhere.
But I can't use it in my model, it gives me the error that I can't use ClientnameLibrary::translate('login') on that place. I added the line App::uses('ClientnameLibrary', 'Lib'); in my model, and tried this in the validate part:
'lastname' => array(
'notEmpty' => array(
'rule' => array('notEmpty'),
'message' => ClientnameLibrary::translate('lastname_validation_error'),
),
),
Is there a way I can use my custom Library in a model? And if not, what is the best way to translate the validation messages in my model (from the database)?
This is the code I use in controllers/views:
App::uses('ClientnameLibrary', 'Lib'); //include at top of file
echo ClientnameLibrary::translate('login'); //to get translated word from database
Save the DB translations in a po file when the translations change. Without caching, reading every translation with a new query is silly, so you will have to cache it any way. So just turn the DB content into a po file and use the standard translation functions from CakePHP?
Check how the i18n shell extracts the translation strings into pot (NOT po) files. You could probably override the shell to update your DB with the required identifiers as well.
Related
Cakephp 2.10 ?
$text = $this->PrivacyPolicy->find('all', array(
'fields' => array('id', 'title', 'description')
));
How PrivacyPolicy is becoming a model role as there is no Model class in the files or relation with the database ?
Magic and unicorn dust... otherwise known as naming conventions and auto-models.
If no concrete model class can be found, CakePHP will create an instance of the AppModel base class instead, which will lookup the database table based on the the model name that you've used. So in your case the AppModel instance will look up the data in privacy_policies (lowercased, underscored, plural variant of the model name).
Quote from the docs:
CakePHP will dynamically create a model object for you if it cannot find a corresponding file in /app/Model. This also means that if your model file isn’t named correctly (for instance, if it is named ingredient.php or Ingredients.php rather than Ingredient.php), CakePHP will use an instance of AppModel rather than your model file (which CakePHP assumes is missing). If you’re trying to use a method you’ve defined in your model, or a behavior attached to your model, and you’re getting SQL errors that are the name of the method you’re calling, it’s a sure sign that CakePHP can’t find your model and you need to check the file names, your application cache, or both.
https://book.cakephp.org/2/en/models.html#understanding-models
In cakephp [2.2] I have baked everything and my "people" view is quite busy with relations and phones and addresses and other related data. I do want all of that information visible in the people view, though not quite in the baked layout.
How should I handle those portions of the related data? I'm not sure if I should use elements or extended views or plugins or what, I'm kinda new to this and the documentation wasn't clear to me (at my level) which should be used when. The baked code seemed to be a monolithic approach, so I didn't get much help looking there.
Once the user chooses to edit a phone number (for instance) from the listing on the person view, it takes them to the phone edit view and then returns them to the phone listing (index view) and not the person view that they were on. How do I get them back to the person view instead?
The blog example they provide is nice, but is there a "reference" application somewhere for cakephp that demonstrates best practices on a wide variety of their features? I couldn't find one, or anything more than just a simple app example.
Thanks, I appreciate the guidance.
This is a rather broad question, but I'm going to try and answer it. I'm not sure how advanced you're programming knowledge is, so forgive me if I'm rehashing things you already know. First, this article was a great help when I started to use the framework for the first time as it explains what code should go where and why. It's the closest I've seen to a "reference application", which would actually be a great learning tool. You could try and have a look at some of the higher profile Cake applications, like Croogo (a Cake-based CMS). But the codebase is bound to be a little bit complex.
Personally I would use elements when you want to actually reuse them in different views. The problem however, is feeding the element its data. There's a method called requestAction, but even the manual states that this should be used with moderation and in combination with caching. The problem is that using a lot of requestAction calls in different elements litters your Controllers with methods and doesn't adhere to the "Skinny Controllers, Fat Models" mantra.
I would put most of the related data calls in their respective Models and call those Model methods from the Controller and feed them to the View. So let's say you want the 10 latest PhoneNumbers and related Users.
You would have a method in your PhoneNumber model which returns an array of users and their phonenumbers. Use the Containable behaviour to limit the number of related models which are returned. The code below is an example, so the practical implementation might vary:
public function getRecentPhoneNumbers($limit=10) {
$phoneNumbers = array();
$phoneNumbers = $this->find('all', array(
'limit' => $limit,
'contain' => array('User'),
'order' => 'PhoneNumber.id DESC'
));
return $phoneNumbers;
}
If the PhoneNumber and User model are properly related you would be able to call getRecentPhoneNumbers() from the User model:
$this->PhoneNumber->getRecentPhoneNumbers(10)
Or from the Users Controller:
$this->User->PhoneNumber->getRecentPhoneNumbers(10)
Say you have an element which shows a list of those 10 numbers and it accepts a variable called $recentPhonenumbers, you then set the variable in the relevant UsersController method with the returned array from the getRecentPhoneNumbers call:
$this->set('recentPhonenumbers', $this->User->PhoneNumber->getRecentPhoneNumbers(10));
This will make it available to the View that contains the element.
The extended views are relatively new (from Cake 2.1 and onwards) and I haven't used them, but seem a great way to create conditional markup.
As for the second question, redirecting the user to the person view, rather than the index view. This is a matter of adjusting the redirect (see the manual for more details) in the edit() method of the Controller. Standard baked edit() methods accept an $id parameter you can use this to redirect to the view() (which probably also accepts an $id paramater).
So the redirect probably looks something like this:
$this->redirect(array('controller' => 'users', 'action' => 'index'));
Change it to:
$this->redirect(array('controller' => 'users', 'action' => 'view', $id));
Is there any way to set a layout to my messages in my model code?
Here is my model:
var $validate = array(
'email' => array(
'rule' => array('email', true),
'message' => 'Please supply a valid email address.'
)
);
This can be done with CakePHP. However, you have your concerns mixed up. The Model is there for data gathering, manipulation and massaging. The layout of the data is under the responsibilities of the View. In CakePHP specifically the Form Helper.
For more info about how to specify your own layout for a data validation message check out:
http://book.cakephp.org/view/1639/options-inputDefaults
They provide a pretty great code sample on exactly how to do this.
I also highly suggest you read through the whole book. It will prove invaluable.
Edit: Answer after clarification from comment
You would create an element and put it in app/views/elements. Should name the file using normal Cake conventions. Let's go with flash_error.
You would set this up to be your HTML that you want displayed. To make sure your message is displayed simply add this bit of PHP wherever is appropriate
<?php echo $message; ?>
That's step 1.
Step 2 is in your $this->setFlash() call pass the appropriate parameters. So your new calls would look like this with the element we named above:
$this->setFlash($message, 'flash_error');
Now your setFlash messages will use the layout defined in step 1. Wanna different layout? Just create a new element and pass the new element name.
The setFlash() method has 2 more parameters that come in handy (particularly if you want to have multiple flash() messages on the same page). Another link to the book:
http://book.cakephp.org/view/1313/setFlash
I was planning my database and since CakePHP hasn't named its classes with its own prefixes, there are many classes that may collison with model classes created according to naming conventions.
So my question is in three parts:
Is there a list of database
table names that are reserved or a
simple way to check if it is? It
would be a pain if I plan database
with 100 tables and notice some of
the tables and their connections would
have to be renamed...
Is there a simple way around it without breaking any CakePHP magic? Is it adviced? Would naming the tables in other way by adding own prefix 'my_' or similar at the beginning of table name the best way?
Is namespaces or something similar coming to
CakePHP version 2 that would allow
use of all kinds of table names?
No, there aren't. Cake doesn't care what you name your tables as long as you adhere to Cake's naming conventions. It generates the schemas it uses for magic model methods the first time a model/s is loaded by a controller; you don't have to lift a finger. See http://book.cakephp.org/view/903/Model-and-Database-Conventions
Best advice: don't fight Cake on this. If you really cannot adhere to to Cake's conventions, you might as well not use Cake; it's stupidly difficult, confusing and succeeding just means you've lost most of Cake's heavy lifting abilities. Pluralizing your table names isn't THAT bad, and Cake will be happy.
This functionality is already available in 1.3 - name your tables anything that pleases you (as long as they're plural words.)
-- You'd probably be well-served to check out baking apps in the console so you can get familiar with what Cake wants to see and how it works on different table layouts.
Edit after clarification:
Your models, controllers, and view directories all share a common name, like so:
// in /app/models/rate.php
class Rate extends AppModel {
var $name = 'Rate';
// in /app/controllers/rates_controller.php -- note the underscore
class RatesController extends AppController {
// controllers are capitalized + plural
var $name = 'Rates';
// in /app/views/rates/*.ctp - Cake's magic autoRender expects to find a view file with
// the same name as the action rendering it - the view for Rates::index() is index.ctp
All of your models extend cake's AppModel class (which extends cake's Model class), no prefix needed. All controllers will extend Cake's AppController class - the class name is suffixed with Controller, and the file name is suffixed with _Controller.
You'll fine AppModel and AppController in /app, and they exist expressly for whatever app-wide custom methods / properties you may have. Since all of your models / controllers extend them, inheritance automatically disperses whatever properties / methods you place in them - for example, Auth. ^_^
But you can still name a table Models, or Controllers, or Views, or whatever, I guess. The $name property is an alias; you can create multiple instances of the same table in the same model by aliasing it with a different name. You can create models without tables, and you can switch between multiple tables - or databases, or servers - in a single model. You can also create non-database-type data objects (such as flat xml files) for your models. Dynamically named classes / methods ($$Model::save(), etc) are what's running under the hood anyway. I've done something similar in iterations for the sake of DRYing up my app and I didn't have a problem. (Although I personally doubt actually pulling off a local model named Model would be worth the effort you'd put into the experiment...)
And on that note, Cake's API spells out all it's classes their methods, etc. (generates off the comments in the codebase):
http://api13.cakephp.org/classes
HTH. :D
I know from experience you can't use table names like 'files' and 'models' because they create classes that are already used by Cake for other things such as File and Model.
I haven't come across any other problems like this but I'm sure they are there to be found.
I would suggest avoiding the use of any name used by cake core classes.
I know this is a bit of an old thread but just came across it searching for something else. I think this shoud help answer question #2. In database.php you can add your db table prefix in the DATABASE_CONFIG class /app/config/database.php. See the last key in the config array below:
var $default = array(
'driver' => 'mysql',
'persistent' => false,
'host' => 'localhost',
'login' => 'user',
'password' => 'password',
'database' => 'database_name',
'prefix' => '',
);
I am working with brownie plugin for cakephp and I would like to know if it is possible to change the names that the CMS show in the menu. By default it takes the name of the database tables, but I want to change the name only to display it in brownie, no modify the table name.
Is any configuration in $brwConfig that changes the name, something like
'fields' => array(
'names' => array('name'=>'new name'),
),
No, it doesn't look like that is the case. Looking at the app_controller for the project, the _menuConfig() function doesn't reference any external configurations when it creates the menu.
If you really want changes, you'd have to modify the plugin to my understanding - there is no way to override specific functions from your main app.