Beginners Question: structurizing the app

Hi,

first: I am a total newbie to Yii.

second: I’ve been coding in php for several years now, creating a webbased app, that is in productive use. I would call myself advanced in php and mysql, but not a pro.

Until now, I never used a PHP-Framework. My app is getting a bit old (codewise) and I want to make a fresh start. To speed things up, I thought I’d use a framework. After researching and trying a while I settled for yii.

After successfully installing, going through the ‘getting started’ section and browsing through the Definite Guide, it’s still hard for me, to understand some of the basic concepts of how MVC really works, and what I have to do step by step, to make things work. I hope it’s not tiring for you pros, if I start asking some dumb sounding questions.

Until now, my app consisted of an index.php, which routed the request to different modules, which means includes where triggered based on the GET-Request sent. It always included several general classes, for example a ‘config.class.php’, a ‘db.class.php’, a ‘sec.class.php’, a ‘log.class.php’, etc… all in which classes with methods and properties were defined and later on used. Systemwide variables were stored in SESSION and before any header was sent, all data was collected, either a html-Output or a pdf-Output using fpdf (or an AJAX-Request, which then was rerouted). At the very end of the ‘index.php’ the output was triggered. The app uses TWO (!) database connections, and all personal data in both databases is BINARY encrypted. The first database contains among other information the decryption-key for the second database.

  1. Question: Is yii working basically the same way? Would the file ‘web\index.php’ be the equivalent to my ‘index.php’?

  2. Is there a need to create a controller for every database-Table, and in that controller, would I have to create all functions for retrieving, updating, securing, encrypting, decrypting and filtering data?

  3. My database consists of many tables with minimal information, these tables are very often connected through indizes, to retrieve data. I often use "INNER JOIN’-Statements to retrieve data from many tables (up to 4, I think) in one request. How would I have to do this in yii? Can there be a controller for the database, like I used a class with many mehtods to retrieve data?

  4. How would I tell yii not to load a view, but rather use fpdf, to create a pdf-File in a new browser window?

  5. Where would I put such a routine: “On every loading of the page, test, if there is at least one user in the database-table ‘user’. If not, load a page, that gives the opportunity to create a user. If there is at least one user, and there is no active login, present a login page. If there is at least one user, and a valid user is logged in, present the regular homepage with different menue items.” - A How to-Guide to these Questions would make yii a lot clearer for me, than the satellite-type ‘Getting Started!’, describing single concepts without tying them to the great picture (no insult intended, it’s just my simple mind, that may not be able to tie the given knots together).

Answers to these questions would be very appreciated and would get me started.

Thanks a lot!!

hbergman

  1. Yes, index.php serves as the entry point for every request to your Yii app.

  2. Controllers and database tables don’t have a direct connection. Your database tables are represented by models AKA ActiveRecords: http://www.yiiframework.com/doc-2.0/guide-db-active-record.html

The controller might tell the model "go save yourself", but the actual database access is then happening in the ActiveRecord.

  1. This might again be something your model would take care of. You can also construct more special queries manually: http://www.yiiframework.com/doc-2.0/guide-db-query-builder.html

  2. http://www.yiiframework.com/doc-2.0/guide-runtime-responses.html#sending-files

  3. The part about whether a user is logged in or not can nicely be solved with AccessFilters: http://www.yiiframework.com/doc-2.0/guide-security-authorization.html

Thanx for the quick answer.

  1. Tables are represented by models. Does that mean, that I create a model script (like my_table.php) in the folder /models/ for each table, I want to work with? And can I define custom functions inside that model (class)? Can I access other tables from within that model? Where should I define functions for encrypting/decrypting fields? They would be the same for each table AKA ActiveRecord. It doesn’t make sense, to define these functions in every mdoel-file. I hope I’m getting the structure right?

  2. This is not about sending a file request, but rather telling yii to use the fpdpf-Class, then invoke a PHP-Script that creates the php-File. How would I use a class like fpdf (or rather mpdf) in yii. Do I Have to create a Controller, a model, an action and a view? (That is still confusing me,… what files do I have to create where to get something to work)

  3. This seems to be already setup in the basic installation with users and passwords written directly into the model-file as a private static variable anmed $users. How could I populate this with users from a database? Could I call an ActiveRecord from within that class? If in SiteController, as shown in the Guide, I would want to check everytime (!) the app is receiving a request, if there is not at least one user, than go to register page, if there is at least one user, but no active login go to login page, if at least one user and active login, process the rest of the request. In which files would I have to write these routines? In the web/index.php, in the cotroller/SiteController.php and where else??? That still confuses me. Sorry, I feel dumb!

hbergman

I’m not quite qualified to answer your questions, since I’m just a user of Yii, while you have been the creator and maintainer of a framework of your own.

But, OK, I will try. :)

The equivalent to your “index.php” might be an Application object which is created in ‘web\index.php’ (Entry Script). But the concept is almost the same as yours.

Read through the Application Structure and Handling Requests sections of the guide, and you’ll get the big picture of the framework.

The Controllers in Yii are very thin glue that connects the necessary objects to handle the requests. They usually don’t do any substantial processing of data. Any data, including one from db, and business logic should be handled in Models.

For database tables, Yii will automatically create the corresponding Active Record models for you by its code generator called "Gii".

But "securing, encrypting, decrypting" are not supported on the database accessing level out of the box. You have to implement them on your own, probably extending ActiveRecord. … I would want to postpone it at least for the moment.

Gii will also create for you a set of controller actions and views that implements CRUD operations on the database table (or ActiveRecord model), in which also a basic filtering logic will be implemented in an additionally created model.

Relational Features of ActiveRecord comes in handy at this point.

With a proper declaration of the relations among tables in ActiveRecord models (usually Gii will do it for you), accessing relational data becomes quite easy.

Sorry, it’s beyond my knowledge. But probably you just have to return a PDF content with a proper response header in the controller action. A view (normal html view) is not automatically loaded unless you explicitly tell it in the controller.

Yii has its own Authentication / Authorization framework. It’s quite solid and flexible. Though you may be confused at first since it differs from yours in its shape, you’ll soon be able to do what you want to do very easily.

Now, that’s all for the moment.

I hope our friends will correct me if I’m wrong and add something important.

[EDIT]

Oh, I was late.

Yes, the approach is called active record: https://en.wikipedia.org/wiki/Active_record_pattern

As softark mentioned, Yii can do that automatically for you by means of a tool called Gii.

Sure

For invoking a third party, see this: http://www.yiiframework.com/doc-2.0/guide-tutorial-yii-integration.html

Try to thoroughly understand MVC before you get too deep into a project. It’s a great concept but it takes some time to wrap your head around it.

Have a look at the advanced template for an idea of how to implement that:

http://www.yiiframework.com/doc-2.0/guide-start-installation.html#other-installation-options

Don’t. You’re merely lacking information.

Play around with Yii, make sure you really understand MVC, then come back to that problem.

Probably you may want to have a customized ActiveRecord class, something like ActiveRecordEx, from which all of your ActiveRecord models will be extended. Your base model should be extended from Yii’s ActiveRecord, and should have generic functionalities of encryption/decryption using the key stored in other database table.

But I think you should not try to do it until you get fairly accustomed to Yii.

Are you thinking about the very first registered user of your application, I mean, the built-in administrative user called “admin”, “root”, “system” or something like that? If so, you’d better consider using Database Migrations for it, because it doesn’t belong to the operational process of the system, but to the application structure itself that is to be developed with source code.

Thanx for all the help, I couldn’t react sooner, cause I wasn’t allowed more than 2 posts within the first 12 hours after regsitration. Thanks a lot. You got me started. I think I’m slowly getting the concept.

There is just one reason for that: I’m trying to learn yii by setting me tasks - that was one of it. You’re right, in a productive setting I wouldn’t need such a functionality. But the second step is absolutely mandatory and shall get me started workiong on the real project. Only logged-In users shall be able to use the app, everyone else shall only get the login page. I was successful in installing and running Dmitry Erofeev’s yii2-user-module (would have linked it, but I’m not yet allowed to post links), which has some nice features. But I’m still wondering where to put the routine to check if a user is signed in, before anything else happens. I mean, as far as I understood, this must be something that is coming before any other controller is getting to work, or I would have to incorporate it in every controller as a behavior with the filter AccessControl?

This will be the last question I post in this thread. Other questions will be more specific and thus have their own thread.

As is usual with any PHP web application, Yii manages the identities of users using session and cookie. The feature is encapsulated in yii\web\User, which usually you can access as Yii::$app->user. It’s an indispensable application component that Yii creates from session and cookie for each and every request. It’s ready to be used by the time a controller action is called.

As a result, you can easily check if the current user is a guest or not. For example, you can write like the following in your controller action:




    if (Yii::$app->user->isGuest) {

        return $this->redirect(['login']);

    }

    return $this->render('index');



Or, you may also check if the user is a guest or not before actually calling controller actions using Access Control Filter. If the filter denies the access to the page to the current user, then the controller action won’t be called.

For a simple scenario, there’s not so much left for us to do.

I guess you have been managing the access control in a different way in your framework. Please read through Authentication and Authorization sections of the guide, before you try to do what you have been doing in your own way.

If I understood the Authorization and Authentication sections right, I would have to put such check into every controller as a behaviour, got that.

In my ‘framework’ I had two different Access Controls: first the basic question whether the user is logged in or not. That was part of the very first routines that were happening. If not, the login page would be presented. After logging in, there were roles as part of the user-profile and the roles determined which parts of the app were accessible to the specific user. In that case each entry-script for each module checked, if the user had the rigth role to access that module or submodule…

If I understood it right, in Yii2 I have to check the basic question whether or not the user is logged in not just once, but in every controller I use, right? Or could I pose that question in web/index.php right after


(new yii\web\Application($config))->run();

? Is there a redirect()-method for the $app-Object as it is in the Controller-Class? That would probably screw up the MVC-Model, right?

In Yii’s authentication/authorization framework, a permission to access certain page (or functionality) can be determined and processed in two ways.

One is ACF (access control filter) that is implemented as a behavior of the controller. With this filter, you can define what actions to grant to what kinds of users. For example, (1) all users including guests can access “index” and “login”, (2) logged-in users can access “list”, “create” and “view”, (3) logged-in users with “admin” role can access “edit” and “delete”. All of these can be defined in the filter. When you are satisfied with this granularity of authorization, you don’t need to do anything more in each action. If a guest tries to access “create” page, then he or she will be redirected to “login” page automatically. And if a normal user tries to access “edit” page, an error page of 401 unauthorized (or 403 forbidden? I’m not sure) will be displayed automatically.

The other is a little tedious but finer-grained flexible way in which you are to check the user’s permission manually. For example, you may want to show different menus in “index” page depending on the user’s role. ACF won’t help you in this respect because it only works per action. So you will write something like the following:




<?php if (Yii::$app->user->can('create')) : ?>

    <?= Html::a('Post a new article', ['post/create']) ?>

<?php endif; ?>

<?php if (Yii::$app->user->can('edit')) : ?>

    <?= Html::a('Edit this article', ['post/edit', 'id' => $post->id]) ?>

<?php endif; ?>



In the above, ‘create’ and ‘edit’ are called ‘permissions’ that represent some right to do something. They are defined in the RBAC (role based access control) hierarchy, and ultimately possessed or not by a certain user via the ‘role’ he/she is assigned.

We don’t need to open our ‘user’ table each time before we apply ACF, or before we call ‘can’ method to check user’s rights, since the auth manager application component will do almost everything for us.

Thank you. I would indeed need both.

The manual way is written into views or layouts, right?

The ACF is found only in controllers and I would have to check in every single controller-behaviour, whether a user is guest or not, right? That would be very repetitive, because, as I understood, in a complex app like mine, there would be many controllers.

As a solution I tried to write something like the following at the very top of ‘/views/layouts/main.php’ (using Yii2’s basic tmeplate)




<?php


/* @var $this \yii\web\View */

/* @var $content string */


 

if (Yii::$app->user->isGuest  && Yii::$app->request->get('r') != 'login'){

  header('Location: http://myapp.com/login');

}

use yii\helpers\Html;

use yii\bootstrap\Nav;

use yii\bootstrap\NavBar;

use yii\widgets\Breadcrumbs;

use app\assets\AppAsset;

AppAsset::register($this);

?>

<?php $this->beginPage() ?>



That didn’t result in anything. It was completely ignored and the request was processed as usual.

By the way, maybe a stupid question, waht does


<?=

do? I never used it before. Tried to google it, and there was ‘no result’, a very remarkable result on a google request. Looks funny!

From the easiest question:


<?=

This stands for


<?php echo

Yes.

Yes, sort of. But you have to write ACF for each and every controller anyway, when you want to give different permissions to different roles.

You seem to be obsessed too much by the idea of “logged-in or not”. What we really have to check is whether the current user has a certain permission or not. Being a guest is only a factor that affects the decision. Although it’s an important factor, but we can handle it just as the same way as we do with those roles like “admin”, “moderator”, “normal user”, etc. No need to handle it differently.

Yii doesn’t expect PHP header() function being called inside a view script.

I want to suggest you to take a look at the following extension:

mdmsoft/yii2-admin

This extension helps you to simplify your ACF jobs by its mdm\admin\components\AccessControl.

Basic Usage