ATK CRUD with one:many relationship - atk4

I'm a beginner and searched documentation, but can't find this how to do this:
I have two tables, admin and application. Admin can have many applications.
ADMIN:
class Model_Admin extends Model_Table {
public $entity_code='admin';
function init(){
parent::init();
$this->addField('name');
$this->addField('email');
$this->addField('password')->type('password');
$this->addField('active')->type('boolean')->system(true);
$this->addField('super')->type('boolean')->system(true);
$this->addField('created')->type('timestamp')->defaultValue($this->dsql()->expr('now()'))->system(true);
$this->addField('updated')->type('timestamp')->system(true);
$this->hasMany('Application','admin_id');
//$this->hasOne('Application');
$this->addHook('beforeSave',function($m){
$m['updated']=$m->dsql()->expr('now()');
});
}
}
APPLICATION:
class Model_Application extends Model_Table {
public $entity_code='application';
function init(){
parent::init();
$this->addField('name');
$this->addField('fbid');
$this->addField('fbsecret');
$this->addField('active')->type('boolean')->system(true);
$this->addField('created')->type('timestamp')->system(true);
$this->addField('updated')->type('timestamp')->system(true);
}
}
First question, when I generate SQL code (/generate.html) it doesn't produce anything for one to many relationship.
Second, on a page I add CRUD:
$this->add('CRUD')->setModel('Admin');
But there is no hint for any one to many. I would expect it on the add button form, but also there is nothing?
What I want is, that I can add admin, and select which applications belong to it?

in Model_Application
$this->hasOne('Admin');
on Page
$this->add('CRUD')->setModel('Application');
In Edit form of CRUD you will see dropdown with all admins and you'll be able to set admin to each application

Related

How to dynamize cucumber value and pass that into the login page

How to dynamize cucumber value and pass that into the login page, for example:
If I use Adam in the cucumber scenario then it should automatically use adam login details and other information and if i use another name it should use that person's information. So i do not have to manually enter it in every step defination. How Can i achieve it?
Scenario: Add an item to shopping bag to place the order using mastercard
Given that "Adam" is logged in to his account
When he searches and adds an item from "men" section to his shopping bag
Then he can place the order
export class LoginUser implements Task {
static called(name: string): LoginUser {
return new LoginUser(name);
}
performAs(actor: PerformsTasks): PromiseLike<void> {
return actor.attemptsTo(
Click.on(homePageElementsMap.lnk_login),
Enter.theValue('test#test.com').into(loginPageElementsMap.txt_login_email),
Enter.theValue('password111').into(loginPageElementsMap.txt_login_pwd),
Click.on(loginPageElementsMap.btn_login)
);
}
constructor(private name: string) {
}
}
disclaimer: this is a java answer, I misread the tag. I am sure you can something similar for js.
For our tests we have a variety of users as well and we use a java class with userdata for this, set up as maps.
We pass the value to a static method public Map<String, String> getUserData(String username) which contains a switch for the variety of users we have, each user is given a map of data we want to use in the tests. The users each have a private Map in the class containing login information.
Of course, there are more scalable ways, this one just gives us the flexibility of a single public getUserData(userName) and behind this we can do with the storage whatever we want.
Short answer: static java code containing user information for a variety of usernames.
Is this the only way to do it? - http://docs.behat.org/en/v2.5/guides/1.gherkin.html

CakePHP, creating extensible Plugin

I have several projects in CakePHP, and would like to move common code into plugins and use seperate GIT repositories for those.
For example, I created a UserManager plugin which contains MVC for users, groups and permissions.
My problem is: the different projects have different (additional) relations to the models from the plugin. E.g., one project should have "User belongsTo Location" in addition.
I'm now confused how to set this up properly. The manual tells how to override Plugin views, but not how this is done with models and controllers.
How can this be done in a clean way?
You can simply extend the plugin classes and override/add the necessary associations, just like you're probably already doing it with AppModel respectively UserManagerAppModel.
http://book.cakephp.org/2.0/en/plugins.html#plugin-models
Here's a basic example (assuming the user class in the plugin is named User):
App::uses('User', 'UserManager.Model');
class AppUser extends User
{
public $belongsTo = array('Location');
}
Or create the associations dynamically in case there are existing ones that need to be kept:
class AppUser extends User
{
public function __construct($id = false, $table = null, $ds = null)
{
parent::__construct($id, $table, $ds);
$this->bindModel(array('belongsTo' => array('Location')));
}
}

Traversing relationships (simple)

Bear with me please, I'm still learning.
I have 4 Models as so:
class Model_Users extends Model_Table {
public $table="users";
function init(){
parent::init();
$this->addField('name')->mandatory('Enter Name');
$this->addField('email')->mandatory('Enter E-Mail');
$this->addField('phone')->mandatory('Enter Phone');
$this->addField('password')->type('password')->mandatory('Enter Password');
$this->addField('is_superadmin')->type('boolean');
$this->addField('is_employee')->type('boolean');
$this->addField('is_manager')->type('boolean');
$this->hasMany('companies');
}
}
class Model_areas extends Model_Table {
public $entity_code='areas';
function init(){
parent::init();
$this->addField('name');
$this->addField('description')->type('text');
//$this->addField('companies_id')->refModel('Model_companies');
$this->hasOne('companies','companies_id','name')->mandatory(true);
$this->hasMany('sites');
}
}
class Model_areas extends Model_Table {
public $entity_code='areas';
function init(){
parent::init();
$this->addField('name');
$this->addField('description')->type('text');
//$this->addField('companies_id')->refModel('Model_companies');
$this->hasOne('companies','companies_id','name')->mandatory(true);
$this->hasMany('sites');
}
}
class Model_sites extends Model_Table {
public $entity_code='sites';
function init(){
parent::init();
$this->addField('name');
$this->addField('description')->type('text');
$this->addField('qrcode');
//$this->addField('Company Name','areas_id')->refModel('Model_companies','name');
$this->hasOne('areas','areas_id','name');
}
}
I have the "sites" model in a simple crud. It is successfully pulling the relevant hasOne record from "areas". I have two questions:
1) How do I change the column names for the joined areas column? It just says "Areas", whereas I want it to be "Area Name"
2) And the more complex one: How can I perform something like a grid->addColumn to the resulting CRUD (or would it have to be a grid?) that would pull the company name linked to the area in areas_id? Its all 1 to many relationships down the line. Company has multiple areas. Areas has multiple sites. I want to add the company name to the CRUD view of Sites.
You can see in the commented lines some of my minor attempts at accomplishing this. Then I realized I'm missing something big. I should be able to keep this model simple and simply traverse the relationships..
Thank you for your help.
Back to these tutorial videos.
Edit: OK the column name I figured out. ->caption('Blah'). Still can't figure out the traversal :(
1) Try:
$this->hasOne('areas','areas_id','name')->caption('Area Name');
2) Slightly simplified your models and here it is. I admit - I didn't test this, but it should work:
<?php
class Model_Company extends Model_Table {
public $table = 'company';
function init(){
parent::init();
$this->addField('name');
$this->addField('description');
$this->hasMany('Area');
}
}
class Model_Area extends Model_Table {
public $table = 'area';
function init(){
parent::init();
$this->addField('name');
$this->addField('description');
$this->hasOne('Company', 'company_id', 'name');
$this->hasMany('Site');
}
}
class Model_Site extends Model_Table {
public $table = 'site';
function init(){
parent::init();
$this->addField('name');
$this->addField('description');
$this->hasOne('Area', 'area_id', 'name');
// join area and company tables
$j_area = $this->leftJoin('area', 'area_id');
$j_company = $j_area->leftJoin('company', 'company_id');
// add fields from joined tables to this model
$j_area->addField('area_name', 'name');
$j_company->addField('company_name', 'name');
}
}
Basic idea - use joins. ->leftJoin will not create joined records, but ->join will create them. Just for reporting (grid, crud etc.) you're fine with leftJoin.
P.S.
Define some kind of coding rules for yourself. For example, when you use uppercase, lowercase, camel-case etc for class names, filenames. Otherwise you'll sooner or later run into problems when moving on *NIX systems.
Good example is to name all classnames with first letter in upper case. Don't forget that your respective file names should exactly match your classname - also letter case.
Page classnames I like to name all in lowercase, because their name is used in URLs and then it looks better lowercased. But that's just me :)
One more. If you're working on new project or are just learning ATK, then stick to newest development version (available on github). There are quite many things which have changed since recording of tutorials. For example $entity_code is deprecated - use $table instead. refModel is obsolete too I guess etc.
If you want to be successful with ATK, then you have to look regularly into ATK source code to understand it better. Also there are some useful comments :)
Good luck!

CakePHP: To Create A New Controller

I'm using CakePHP 2.0.5 (but this isn't necessarily a cakephp specific question). I have a Coupon and a User model. Each time a user prints a coupon (proccessed by: Coupon Controller):
class CouponsController extends AppController {
public function printcoupon($id = null) {
// code
}
}
I want to save the information to a "coupons_printed" table (id/coupon_id/user_id/created). Should I create a new model for this, or should I just create a function inside of the Coupon model similar to (and call it in the controller each time that page is viewed)?:
class Coupon extends AppModel {
function insertIntoPrinted($id) {
$this->query("UPDATE coupons_printed SET .....");
}
}
Whatever you do, a raw SQL query is not the best way to go. Always use CakePHP methods if at all possible (and almost always it is possible).
You should put the insertIntoPrinted() function in the CouponsPrinted model (although, as a side note, PrintedCoupon would be a more natural way to name the model...) You can then add a HasMany relationship to the Coupon model ($hasMany = array( 'CouponsPrinted' )) and call the function in the CouponsController:
public function printcoupon($id = null) {
$this->Coupon->CouponsPrinted->insertIntoPrinted( $id );
}
CakePHP's model has a thing call association.
In your case, Coupon has a hasMany association with coupons_printed.
You can create a new model, or query using the association in the Coupon model, the generated queries will be the same, I believe.
Your CouponsController already depend on Coupon Model, so not creating another model is a better solution.

Generating pages from a database

I'm looking for some help understanding how to generate pages from a database to create a catalog of items, each with different URLs. All I can seem to find through google are products that will do this for me, or full e-commerce solutions. I don't want a shopping cart! Just an inventory.
Also, perhaps someone could recommend their favorite/the best simple login solution.
Thank you so much for your time and any help, suggestions, comments, solutions.
I just posted a thorough solution to another question that is very closely-related to this question. I'll re-post it here for your convenience:
I would suggest using some of the MVC (Model, View, Controller) frameworks out there like KohanaPHP. It is essentially this. You're working in a strictly Object-Oriented environment. A simple page in Kohana, build entirely from a class would look like this:
class Home_Controller extends Controller
{
public function index()
{
echo "Hello World";
}
}
You would then access that page by visiting youur url, the class name, and the method name:
http://www.mysite.com/home/ (index() can be called after home/, but it's implicit)
When you start wanting to bring in database-activity, you'll start working with another Class called a Model. This will contain methods to interact with your database, like the following:
class Users_Model extends Model
{
public function count_users()
{
return $this->db->count_records('users');
}
}
Note here that I didn't write my own query. Kohana comes with an intuitive Query Builder.
That method would be called from within your Controller, the first class that we mentioned at the beginning of this solution. That would look like this:
class Home_Controller extends Controller
{
public function index()
{
$usersModel = new Users_Model;
$userCount = $usersModel->count_users();
echo "We have " . $userCount . " users!";
}
}
Eventually, you'll want more complicated layouts, which will involve HTML/CSS/Javascript. At this point, you would introduce the "Views," which are just presentation layers. Rather than calling echo or print from within the Controller, you would load up a view (an HTML page, essentially) and pass it some variables:
class Home_Controller extends Controller
{
public function index()
{
$myView = new View("index");
$usersModel = new Users_Model;
$userCount = $usersModel->count_users();
$myView->userCount = $userCount;
$myView->render(TRUE);
}
}
Which would load the following "View"
<p>We have <?php print $userCount; ?> users!</p>
That should be enough to get you started. Using the MVC-style is really clean, and very fun to work with.
There's a lot of tools out there for generating a web interface around a data model. I find Django pretty easy to use. Based on its popularity, I'm sure that Ruby on Rails is another viable option.

Resources