Yii2 MySQL table names and HTTP404 errors - mysql

I am new to the Yii technology, but having worked in IT for many years I hoped I understood generally how software is designed. But the Yii guys have got me good.
I have been trying to understand why I am getting HTTP404 errors.
I have a Win 10 environment using MySQL, with latest versions of MySQL and PHP. I naively assumed that Yii would support the nomenclature standards for objects in the MySQL, especially table names. However it appears I am wrong, so here is a heads up for those interested.
I use all lower case characters for my table names, and where I have a table that is a link between two entities I use a name such as entity1_entity2. I use gii to generate a model from this table and the the CRUD option to generate a basic initial application.
I have the pretty URL active, so the initial URL I use is :
\localhost\Movies\movieactor
Where Movies is the website name defined to IIS (virtual directory) and movieactor is the lowercase name I used for the model and controller objects. The actual name prefix I used was MovieActor for the model and controller objects. I used movieactor for the view sub-directory.
Much to my surprise I was presented with an HTTP404 error message. I spent most of a day trying to understand what I had done wrong.
After a good sleep, I started again the next morning. I decided to try changing the name of the relevant table from movie_actor to movieactor. I then regenerated the model, and CRUD components. This time when I invoked the same URL I was pleasantly surprised to see the web application show me the data.
I have no idea what restrictions the Yii guys place on table names, no documentation that I can find, but this is my experience, and hopefully it may save others some grief.
Have I missed something or is my story correct ?

First of all in Yii there are no requirements for table names. Table or model class names are not directly related to URLs.
When you are using gii to generate model you are prompted to enter the table name. Then the model name is suggested as pascal case version of table name. For example if your table is named movie_actor the suggested model class name will be MovieActor. But you don't have to accept that, you can change it to whatever you want.
Then when you are generating CRUD it asks you to enter model class, search model class and controller class. The model class here is the MovieActor generated earlier. Search model class can be whatever you like, but what is important for URL is the controller class. There is something called controller id based on controller class name. It's a kebab case version of controller class name after removing the Controller suffix. If you name your controller as MovieActorController its controller id will be movie-actor. It's this controller id that you need to use in your url to reach that controller. So, url you have to use for this controller would be \localhost\Movies\movie-actor. You need to use same controller id as a sub-directory for your views too.
When you've decided to change table name to movieactor you've probably also generated the controller as MovieactorController. Because of that its id was movieactor and your url and views subfolder were correct.

Related

Programatically tell if a view has a model declared, the model type and whether its null

I investigated using an IAsyncResultFilter and using it's OnResultExecutionAsync method to look at the context.Result.Model but unfortunately if the context.Result.Model is null there is no way for me to tell if it's null because no model was declared for the view or because even though one was declared it's null because no model was passed to the view.
Since the Razor View get's compiled before it executes it seems that there should be some stage of the render pipeline where that resultant class can be interacted with and where I can perhaps get the info I need from that class? But how?
How can I programmatically tell if a view has a model declared, what the model type is and whether the model is null for the current rendering of the view?
As Chris Pratt pointed out in the comments, it might help to understand what the motivation for such a question is. So here is the back story:
Generally speaking the web application I'm working on has two types of views. 1) views that have view models and that are routed to via an attribute based route specified in the controller and 2) views that that do not have a view model declared and which are routed to by a default route which is handled by a default controller which finds the view based on the url path specified in the request.
This approach works great most of the time, but if I have a view that requires a model and I have a typo in the attribute based route or forget to specify it altogether in the related controller, then the default controller will kick in and try to serve that view but with a null model. This causes the razor page to throw a generic null reference exception and I'd like to enhance that error message so that it gives better info about the situation. Namely that the view expects a model but the model was null. So if I could detect the situation I could throw a more detailed exception that would aid in faster problem identification.

Yii2 best practices translating dynamic content

Can anyone share own experience and best practices implementing multilingual sites with Yii2? I want translate user input that is stored in database. For example article, that may have its name in three different languages, body and some translatable attributes as well.
Does Yii2 have built in features to translate the dynamic content? Or should I use third party extensions like these ones below:
https://github.com/creocoder/yii2-translateable
https://github.com/LAV45/yii2-translated-behavior
https://github.com/lajax/yii2-translate-manager
Your help would be appreciated.
Well, I can give you my point of view only based on what I have done.
There are to places to work translation
The non dynamic strings managed with i18n and messages system from
yii, that will help you with static content.
Working the translated routes dynamically with a bootstrapped class, that allows you to build this routs when the app is built.
And working with tables that have columns that support the translation like 'title_en, title_es', and as many as you need to translate. Actually in your admin interface you may want to use something like yandex to help you translating the content to this fields.
Now I will explain:
The i18n Message Translation is based on translating strings in your views, models, and in some cases like on the bootstrapped class.
You will en using Yii::t('app/main', 'Your name is {0}' as an example to translate strings that are stored on message php files.
Now if you translate stings you will want to translate the routes so you will en with routes like /articles and /articulos when you change the language.
for this purpose you will like to build a class that implements BootstrapInterface and that will be called from the process of bootstrapping your app.
So this is an example of my settings.php that I use for this
namespace app\base;
use Yii;
use yii\base\BootstrapInterface;
class settings implements BootstrapInterface {
public function __construct() { }
public function bootstrap($app) {
/// Dynamic translated routes
$t_articles = Yii::t('app/route', 'articles');
$app->getUrlManager()->addRules([
'/'.$t_articles => '/articles',
], false);
}
}
And remember to bootstrap the class in your config file «i.e. web.php»
'bootstrap' => [
'log',
'app\base\settings',
],
And finally to translate text from the database you may want to make a table that supports the translated text like:
CREATE TABLE articles (
id INT,
title_en VARCHAR(20),
title_es VARCHAR(20)
);
So when you call your app you can pull your data using something like the following on the action (only a simple example):
$articles = ArticlesA::find()->where(['id' => 1])->one();
$lang = $this->module->language;
return $thi
s->render('index',['articles'=>$articles, 'lang'=>$lang]);
or in the view as:
<p class="lead"><?=$articles['title_'.$lang]?></p>
I hope this explains the way I have been translating my apps.
Use a Google translator API or Yandex API to for smooth translations for multiple languages.
Few links that i have found on git
https://github.com/borodulin/yii2-i18n-google
Tutorial
RichWeber/yii2-google-translate-api
Google Api is a paid service however you can get free credit for 12 months if your a first time user

JTreeTable model updating

I'm following the example of JTreeTable filesystem2 taken from the sun site http://java.sun.com/products/jfc/tsc/articles/treetable2/index.html#updating_the
My problem is that I can't update my model (and then my JTreeTable)...
In fact I create my model, I pass it to the JTreeTable and all work fine...but I need to modify the model...
I've yet answer a similar question, but now I've changed my code, without find a solution.
The problem is when and how I have to call the method fireTreeNodesChanged()...in the example above is used the method getPath() to retrieve information about the root node...but this is a method of File class..not my case...
Does anyone have a link to a simple code which shows how create a TreeTabelModel (with objects as nodes) and how update it?
FileBrowser is a good example of modeling a hierarchical file system as a tree. While its TreeModel is implemented using DefaultTreeModel, an alternative FileTreeModel is shown here. As mentioned in How to Use Trees: Creating a Data Model "the TreeModel interface accepts any kind of object as a tree node."

entity framework code first and database user

We're running into a small problem deploying a web application to another environment.
We created the application's db using Entity Framework Code First approach (db automatic created from Model).
In this development environment, we are using integrated security and the tables are created under the dbo user. The tables are like
[dbo].[myTable]
For our other environment, we are using username/password authentication for the DB.
We scripted the tables and created them on the DB. So they are now named like
[myDbUser].[myTable]
When running the application, we encounter always the problem
Invalid object name 'dbo.myTable'.
Seems like the code is still trying to look for a dbo table, which is not present and thus fails.
Can anyone shed some light on this problem? Where does Entity Framework gets this dbo prefix from?
Thanks
Specify schema explicitly:
[Table("Users", Schema = "dbo")]
public class User { .. }
Or specify default db schema for your user - 'dbo'
To specify schema in fluent
protected override void OnModelCreating(DbModelBuilder modelBuilder)
modelBuilder.Entity<ClassName>().ToTable("TableName", "SchemaName");
I ran into this issue recently as well as we support several different schemas with the same model. What I basically came up with was the passing the schema name to the classes/methods that map the model. So for example, EntityTypeConfiguration subclasses take the schema name as a constructor argument, and pass it along with the hard-coded string to ToTable().
See here for a more detailed explanation: https://stackoverflow.com/a/14782001/243607

Associating an Object with other Objects and Properties of those Objects

I am looking for some help with designing some functionality in my application. I already have something similar designed but this problem is a little different.
Background:
In my application we have different Modules. Data in each module can be associated to other modules. Each Module is represented by an Object in our application.
Module 1 can be associated with Module 2 and Module 3. Currently I use a factory to provide the proper DAO for getting and saving this data.
It looks something like this:
class Module1Factory {
public static Module1BridgeDAO createModule1BridgeDAO(int moduleid) {
switch (moduleId)
{
case Module.Module2Id: return new Module1_Module2DAO();
case Module.Module3Id: return new Module1_Module3DAO();
default: return null;
}
}
}
Module1_Module2 and Module1_Module3 implement the same BridgeModule interface. In the database I have a Table for every module (Module1, Module2, Module3). I also have a bridge table for each module (they are many to many) Module1_Module2, Module1_Module3 etc.
The DAO basically handles all code needed to manage the association and retrieve its own instance data for the calling module. Now when we add new modules that associate with Module1 we simply implement the ModuleBridge interface and provide the common functionality.
New Development
We are adding a new module that will have the ability to be associated with other Modules as well as specific properties of that module. The module is basically providing the user the ability to add their custom forms to our other modules. That way they can collect additional information along with what we provide.
I want to start associating my Form module with other modules and their properties. Ie if Module1 has a property Category, I want to associate an instance From data with that property.
There are many Forms. If a users creates an instance of Module2, they may always want to also have certain form(s) attached to that Module2 instance. If they create an instance of Module2 and select Category 1, then I may want additional Form(s) created.
I prototyped something like this:
Form
FormLayout (contains the labels and gui controls)
FormModule (associates a form with all instances of a module)
Form Instance (create an instance of a form to be filled out)
As I thought about it I was thinking about making a new FormModule table/class/dao for each Module and Property that I add. So I might have:
FormModule1
FormModule1Property1
FormModule1Property2
FormModule1Property3
FormModule1Property4
FormModule2
FormModule3
FormModule3Property1
Then as I did previously, I would use a factory to get the proper DAO for dealing with all of these. I would hand it an array of ids representing different modules and properties and it would return all of the DAOs that I need to call getForms(). Which in turn would return all of the forms for that particular bridge.
Some points
This will be for a new module so I dont need to expand on the factory code I provided. I just wanted to show an example of what I have done in the past.
The new module can be associated with: Other Modules (ie globally for any instance of that module data), Other module properties (ie only if the Module instance has a certian value in one of its properties)
I want to make it easy for developers to add associations with other modules and properties easily
Can any one suggest any design patterns or strategy's for achieving this?
If anything is unclear please let me know.
Thank you,
Al
You can use springs Dependency Injection feature. This would help you achieve the flexibility of instantiating the objects using an xml configuration file.
So, my suggestion would be go with the Springs.