When programming OO in PHP i never know exactly how to map a class to simple lists of data. I will try to make a simple example wich i am running into every day:
First the MySQL table creates:
/* create product table */
CREATE TABLE `product` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`name` varchar(100) COLLATE utf8_unicode_ci NOT NULL,
`description` text COLLATE utf8_unicode_ci,
`price` decimal(10,0) NOT NULL,
`brand` int(11) NOT NULL,
`deliverytime` int(11) NOT NULL,
PRIMARY KEY (`id`)
) ENGINE=MyISAM DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci
/* data list for all kind of brands */
CREATE TABLE `brand` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`brand` varchar(100) COLLATE utf8_unicode_ci NOT NULL,
PRIMARY KEY (`id`)
) ENGINE=MyISAM AUTO_INCREMENT=6 DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci
/* brand data*/
insert into `brand`(`id`,`brand`) values (1,'nike'),(2,'adidas'),(3,'diesel'), (4,'dkny'),(5,'lacoste');
/* data list for deliverytime */
CREATE TABLE `deliverytime` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`deliverytime` varchar(100) COLLATE utf8_unicode_ci NOT NULL,
PRIMARY KEY (`id`)
) ENGINE=MyISAM DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci
/* deliverytime data */
insert into `deliverytime`(`id`,`deliverytime`) values (1,'1 day'),(2,'2 days'),(3,'3 days'),(4,'4 days'),(5,'5 days'),(6,'6 days'),(7,'1 week'),(8,'1 - 2 weeks'),(9,'2 - 3 weeks'),(10,'4 - 5 weeks');
Then i create the product class.
class Product{
private
$name,
$description,
$price,
$brand
$deliverytime;
public function __construct(){
// etc etc
}
public function save(){
// save the product
}
}
Now the big question(s) are:
How should i handle $brand and $deliverytime in my Product class?
Should i make a Brand and DeliveryTime object (wich in turn are responsible for fetching the right brand and or deliverytime data)?
And what about saving the Product object?
How should i handle the brand and deliverytime data?
What is the beste practice or pattern to handle this kind of situations?
Sorry for this noobish question but i wasnt sure where to look for (tags to search for) :/
EDIT:
Ok lets say i dont want to use somekind of ORM framework (Doctrine, dORM, redbean etc) since it would be a gigantic overkill for my little system + i am realy want to know how to create the mapping myself for learning purposes... any suggestions?
This is a style I like to use
class ProductModel {
public function find($id) {
// fetch product with your database code using parameters to filter
$product = new ProductEntity(
// initialize with non foreighn values (eg. $row->id, $row->name)
new ProductBrandEntity($row->brand_id, $row->brand_name); // available because you joined brand??
new ProductDeliveryTime(/* initialize */)
);
return $product;
}
}
I like to call the object from the database Entities but you can call them whatever you want.. It's basically what you suggested in your question but i prefer to have a Model (from MVC) to initialize the entities and not the entities initializing themselves. You should do some research on ORMs and ActiveRecord because this work has basically already been done for you!
Related
I have a simple ACL system in PHP and MYSQL started. I need help finishing it though...
I have 2 Database tables shown below...
user_link_permissions : Holds a record for every user, on every entity/link that permissions apply to...
--
-- Table structure for table `user_link_permissions`
--
CREATE TABLE IF NOT EXISTS `user_link_permissions` (
`id` int(100) NOT NULL AUTO_INCREMENT,
`user_id` int(30) NOT NULL,
`link_id` int(30) NOT NULL,
`permission` int(2) NOT NULL DEFAULT '0',
KEY `id` (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1 AUTO_INCREMENT=2055 ;
intranet_links : Is basically the entity that the permission gives or revokes user access to
--
-- Table structure for table `intranet_links`
--
CREATE TABLE IF NOT EXISTS `intranet_links` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`title` varchar(255) DEFAULT NULL,
`description` text NOT NULL,
`url` varchar(255) DEFAULT NULL,
`notes` text,
`user_login` varchar(255) DEFAULT NULL,
`user_pw` varchar(255) DEFAULT NULL,
`active` int(2) NOT NULL DEFAULT '1',
`sort_order` int(11) DEFAULT NULL,
`parent` int(10) NOT NULL DEFAULT '1',
`local_route` varchar(255) DEFAULT NULL,
PRIMARY KEY (`id`),
UNIQUE KEY `id` (`id`),
UNIQUE KEY `local_route` (`local_route`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1 AUTO_INCREMENT=34 ;
To save these permissions settings I have a matrix style grid like this below where each checkbox is a record in the user_link_permissions table...
I need help creating a simple ACL function in PHP which can check if a user has permission or not to view a link/entity based on the database results.
On page load I am thinking I can query the user_link_permissions DB table for all records with a matching user ID of the logged in user and store them to a session array variable.
A function could then use that array to check for a link/entity permission using that array value on the entity key.
I just can't visualize how it might look at the moment in PHP.
Any help please?
function aclCanAccess($user_id, $entity_id){
}
$entity_id = 123;
if(aclCanAccess(1, $entity_id){
// yes user can see this item
}else{
// NO user permission denied
}
I will leave writing the code to you for fun.
Assume you are storing all the previously queried permissions in a variable called $_SESSION['acl']
Your ACL function should:
check the session if you already queried that entity
if it is not set, read it from the db
in short
function..... {
if(!isset($_SESSION['acl'][$entity_id])) {
$_SESSION['acl'][$entity_id] = query here to return to you if he has access or not
}
return $_SESSION['acl'][$entity_id];
}
You can also read the entire array when you log in the user. That might also be appropriate. In that case you should be able to just
return $_SESSION['acl'][$entity_id];
But I would then try and catch an exception in case it is not set.
Hi I have these two tables that I want to join using relations in Yii, The problem is Im having a hard time figuring out how Yii relation works.
picturepost
id
title
link_stat_id
linkstat
id
link
post_count
I also have a working SQL query. This is the query I want my relation to result when I search when I want to get picturepost
SELECT picturepost.id, picturepost.title,linkstat.post_count
FROM picturepost
RIGHT JOIN linkstat
ON picturepost.link_stat_id=linkstat.link;
I want something like this when I search for a post.
$post = PicturePost::model() -> findByPk($id);
echo $post->linkCount;
Here's my table for extra info:
CREATE TABLE IF NOT EXISTS `picturepost` (
`id` bigint(20) unsigned NOT NULL AUTO_INCREMENT,
`title` text COLLATE utf8_unicode_ci DEFAULT NULL,
`link_stat_id` char(64) COLLATE utf8_unicode_ci NOT NULL
) ENGINE=MyISAM;
CREATE TABLE IF NOT EXISTS `linkstat` (
`id` bigint(20) NOT NULL AUTO_INCREMENT,
`link` char(64) COLLATE utf8_unicode_ci NOT NULL,
`post_count` int(11) DEFAULT '0',
PRIMARY KEY (`id`),
KEY `post_count` (`post_count`),
KEY `link_stat_id` (`link`)
) ENGINE=InnoDB;
Thanks in advance I hope I explained it clearly.
There are a few tutorial regarding this, and I won't repeat them, but urge you to check them out.
The easiest starting point will be to create your foreign key constraints in the database, then use the Gii tool to generate the code for the model, in this case for the table picturepost.
This should result in a class Picturepost with a method relations(),
class Picturepost extends {
public function relations()
{
return array(
'picturepost_linkstats' => array(self::HAS_MANY,
'linkstat', 'link_stat_id'),
);
}
This links the 2 tables using the *link_stat_id* field as the foreign key (to the primary key of the linked table).
When you are querying the table picturepost, you can automatically pull in the linkstat records.
// Get the picturepost entry
$picturepost = PicturePost::model()->findByPk(1);
// picturepost_linkstats is the relationship name
$linkstats_records = $picturepost->picturepost_linkstats;
public function relations()
{
return array(
'linkstat' => array(self::HAS_ONE, 'Linkstat', array('link_stat_id'=>'link')),
);
}
More on yii relations.
This assumes that you have an active record model Linkstat that represents data in table linkstat.
I would like to implement class (multi) table inheritance in Yii but i found it very difficult, so i planned to use the approach of MySQL view.
Here is an example of my tables and classes:
CmsAd is a table that inherits all the fields included in CmsContent table:
CREATE TABLE `CmsAd` (
`Id_CmsAd` varchar(32) NOT NULL,
`Image` varchar(300) DEFAULT NULL,
`Id_PrdClass` varchar(32) DEFAULT NULL,
`Id_PrdCatalog` varchar(32) DEFAULT NULL,
PRIMARY KEY (`Id_CmsAd`),
) ENGINE=MyISAM DEFAULT CHARSET=utf8;
CREATE TABLE `CmsContent` (
`Id_CmsContent` varchar(32) NOT NULL,
`ModifiedBy` varchar(32) DEFAULT NULL,
`ModifiedOn` datetime DEFAULT NULL,
`CreatedBy` varchar(32) DEFAULT NULL,
`CreatedOn` datetime DEFAULT NULL,
`Status` varchar(99) DEFAULT NULL,
`Subject` varchar(350) DEFAULT NULL,
`Text` longtext,
`KeyWord` varchar(300) DEFAULT NULL,
`Code` varchar(340) DEFAULT NULL,
PRIMARY KEY (`Id_CmsContent`),
) ENGINE=MyISAM DEFAULT CHARSET=utf8;
CmsAd_View is a MySQL view that contains the join of those two tables :
CREATE VIEW `CmsAd_View` AS SELECT `CmsAd`.*, `CmsContent`.* FROM `CmsAd` LEFT JOIN `CmsContent` ON `CmsContent`.`Id_CmsContent` = `CmsAd`.`Id_CmsAd`;
Here are the models of those tables :
class CmsAd extends CActiveRecord {
public function tableName() {
return 'CmsAd_View';
}
}
class CmsContent extends CActiveRecord {
public function tableName() {
return 'CmsContent';
}
}
Notice that the table name of CmsAd is the view CmsAd_View.
Now I would like implement the CRUD the CmsAd. It's ok with find() method because it retrieves from the view CmsAd_View.
My Problem is with insert() and update() methods where we have to insert and update both tables CmsAd and CmsContent.
Is there any one who tried to implement the view approach of table inheritance in Yii ?
I'm new to zend framework, i'm trying to understand how table relationships work. I have two tables and i'm trying to link them and get their data in a list.
CREATE TABLE `relationship` (
`relationship_id` int(10) unsigned NOT NULL AUTO_INCREMENT,
`relationship_name` varchar(45) NOT NULL,
`relationship_group_id` int(10) unsigned NOT NULL,
`display` int(10) unsigned NOT NULL DEFAULT '1',
PRIMARY KEY (`relationship_id`),
KEY `FK_relationship_1` (`relationship_group_id`),
CONSTRAINT `FK_relationship_1` FOREIGN KEY (`relationship_group_id`) REFERENCES `relationship_group` (`relationship_group_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
CREATE TABLE `relationship_group` (
`relationship_group_id` int(10) unsigned NOT NULL AUTO_INCREMENT,
`relationship_group_name` varchar(45) NOT NULL,
`display` int(10) unsigned NOT NULL DEFAULT '1',
PRIMARY KEY (`relationship_group_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
In my relationship table class, I have:
class Relationship_Table extends Zend_Db_Table_Abstract
{
protected $_rowClass = 'Relationship';
protected $_name = 'relationship';
In my relationship group table class I have:
class Relationship_Group_Table extends Zend_Db_Table_Abstract
{
protected $_name = 'relationship_group';
protected $_rowClass = ' Relationship_Group';
I am not sure what my $_referenceMap and $_dependentTables should say, and if I need to state them in both classes or just one?
Also how do I get a list from my relationships table with the corresponding relationship_group data included.
Any help is appreciated.
Here is a pretty good primer on table relationships.
Mat McCormisck on Table relationships in Zend Framework
The actual answer to your question is:
It depends on what you need to accomplish and how do you want to accomplish it.
$_dependentTables aren't required in your case (using InnonDB).
Zend References
Note: Skip declaration of $_dependentTables if you use referential integrity constraints in the RDBMS server to implement cascading operations
Your $_referenceMap should link FOREIGN KEY in a dependent table to the PRIMARY KEY in the parent table and it's only required in the dependent table.
The rest is as RockyFord suggested in his link :).
A bit new to yii and have been having trouble trying to do a join query in my gii-generated model.
Summary:
I want to return videos (table 'videos') that have met specific search criteria. To do this, I have my 'videos' table, and I have another table 'searchmaps'. All searchmaps does is associate a video_id to a search_id so that I can keep track of multiple videos that met criteria for a single search scenario..
What I've tried:
I tried following yii docs for relational queries but I guess I'm missing something still... Below is my code. What am I doing wrong??
(Note: I wish to return a model using CActiveDataProvider)
Tables:
CREATE TABLE IF NOT EXISTS `videos` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`user_id` int(11) NOT NULL,
`directory` varchar(255) COLLATE utf8_unicode_ci NOT NULL,
`created` varchar(20) COLLATE utf8_unicode_ci NOT NULL,
`title` varchar(255) COLLATE utf8_unicode_ci NOT NULL,
`description` varchar(255) COLLATE utf8_unicode_ci NOT NULL,
`category` int(2) NOT NULL,
`tags` varchar(255) COLLATE utf8_unicode_ci NOT NULL,
`filename` varchar(255) COLLATE utf8_unicode_ci NOT NULL,
`filetype` varchar(255) COLLATE utf8_unicode_ci NOT NULL,
`duration` int(11) NOT NULL,
`status` int(1) NOT NULL,
`error` text COLLATE utf8_unicode_ci NOT NULL,
PRIMARY KEY (`id`)
) ENGINE=MyISAM DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci AUTO_INCREMENT=17 ;
CREATE TABLE IF NOT EXISTS `searchmaps` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`search_id` int(11) NOT NULL,
`video_id` int(11) NOT NULL,
PRIMARY KEY (`id`)
) ENGINE=MyISAM DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci AUTO_INCREMENT=69 ;
Classes:
Here is the Controller class:
//From VideosController.php
...
public function actionIndex($searchmap_id)
{
$dataProvider = new CActiveDataProvider('SearchVideos', array(
'criteria' => array(
'with' => array('search.video_id','search.search_id'),
'together' => true,
'condition'=>'videos.id = search.video_id AND search.search_id='.$searchmap_id,
)));
$this->render('index',array(
'dataProvider'=>$dataProvider,
));
}
Below is the main model class:
// From Videos.php
...
/**
* #return array relational rules.
*/
public function relations()
{
// NOTE: you may need to adjust the relation name and the related
// class name for the relations automatically generated below.
return array(
'search'=>array(self::BELONGS_TO, 'Searchmaps', 'video_id'),
);
}
Here is the model class of the related table
// From Searchmaps.php
...
/**
* #return array relational rules.
*/
public function relations()
{
// Each row has a search_id and a video_id relating to a specific video
// Multiple rows may have different videos but share the same search_id
return array(
'video'=>array(self::HAS_ONE, 'Videos', 'video_id'),
);
}
First, I would suggest using InnoDB tables so you can set up proper foreign keys -- if you do this then gii will generate the basic relations for you. If you can convert your tables, then you can add the fk with:
ALTER TABLE `searchmaps`
ADD CONSTRAINT `searchmaps_ibfk_1` FOREIGN KEY (`video_id`) REFERENCES `videos` (`id`) ON DELETE RESTRICT ON UPDATE CASCADE;
Your relations don't look quite right, seems like they should be:
in Videos model:
return array(
'searchmaps' => array(self::HAS_MANY, 'Searchmaps', 'video_id'),
);
in Searchmaps model:
return array(
'video' => array(self::BELONGS_TO, 'Videos', 'video_id'),
);
then your dataProvider can look something like:
$dataProvider=new CActiveDataProvider('Videos',array(
'criteria'=>array(
'with'=>'searchmaps',
'together' => true,
'condition' => 'searchmaps.search_id='.$search_id,
)
));
to try it you can output a simple grid in your view with something like:
$this->widget('zii.widgets.grid.CGridView', array(
'id'=>'videos-grid',
'dataProvider'=>$dataProvider
));
Again, I would highly recommend using foreign keys in your table and view the relations gii outputs and once you understand what it's doing, it will be much easier to customize. Also, using foreign keys will insure the relationships are maintained. You can use a tool like MysqlWorkbench or similar if you need help creating the foreign keys.