Jump to content
Larry Ullman's Book Forums

Jonathon

Members
  • Posts

    1064
  • Joined

  • Last visited

  • Days Won

    55

Posts posted by Jonathon

  1. Hello guys,

     

    This was my conundrum. My users could just be regular people, or they could belong to a company. So in theory 1 user could only have at most 1 company. (A constraint, I need to actually add into my DB.) So you would go for the additional FK in the user table approach. then Yii will create a relation (one i were to reload the the Model in Gii). If a user doesn't belong to a company would you have the FK column return NULL or 0.

  2. Hi Thomas,

     

    Sure can help, I'm using a "company page" to list items. So thje table structure is like this:

     

    Working backwards I suppose, I have:

     

    Company table (each id is a company record) -> Company/user (intermediate table, as a user doesn't have to belong to a company, FK for company id and FK for suer id) -> user table <- Item table (FK is user id who listed)

  3. Hi,

     

    As part of my attempt to understand and how to do things in Yii better. I wondered about this. If you have some intermediate tables in your schema. You often won't have a direct relation() with some models. What is the way around this? Is it to just almost chain models together to get to the information you require. Or would a DAO be more suitable as the query becomes more complex? Or something else?

     

    Hope that makes sense. (Probably doesn't)

     

    Thanks

     

    Jonathon

  4. Right,

     

    To update this situation again. I was having a think about it last night. My problem seemed to be that I was picking up all the Areas from the DB when I only needed one. So I went back and altered my model to

     

     

     
            $model = Area::model()->with('areaItems')->find('t.id=:id', array(':id'=>$id));
    
    

    This only selects the chosen area by an ID value and then all the items that have this location id. Rather than selecting all of the areas and then just filling up each area array with items.

     

    So in my view I can now do this

     

    <h1>
    <?php if(!isset($model->area)){ // $model is NOT returned throw error
    	throw new CHttpException(404,'The requested page does not exist.'); 
    }else{ // $model is returned continue
    	echo CHtml::encode($model->area); 
    	} 
    ?> 
    Items</h1>
    
    

     

    and then iterate through the items in that area if there are any by using the relationship name within the model.

     

    // Are there any items in this area?
    if (empty($model['areaItems'])): ?>
    
    	<p>Currently there are no Items in the area</p>
        
    <?php else: ?>
    
    <?php	
    // $model['areaItems'] is NOT empty so items are iterated through
    		foreach($model['areaItems'] as $row): ?>
    	
                <h2><?php echo $row['title']; ?></h2>
                <p><?php echo $row['descripion']; ?></p>
    	
    		<?php endforeach; ?>
    <?php endif; ?>
    
    

     

    I removed the $id in the controller now. The controller just calls the model function and passes the returned model to the view.

     

    Thanks

     

    Jonathon

  5. Morning Gents,

     

    To confirm the process i'm currently using does work. But Larry was questioning my use of the $id variable to help select the right array. So I was just trying to explain it better for him so he could say yeah that's ok, or no, it's a horror show. :lol:

     

    Thomas, thanks for your input, I do much prefer using Query builder, but I had problems trying to echo out just the $title within a foreach loop and then accessing the foreach loop again. (CDbDataReader cannot rewind. It is a forward-only reader.). But I shall look into what you say thank you.

     

    Edward, I read what you said before and thought, I shouldn't give up on AR so easily so I went back to try and get it to work. It was simple to get the results out I suppose, far less code, but I did find it harder to access as you said you'd found. I prefer QB personally, but the only issue I find with it is you can only use the foreach loop once. Which makes printing the <h1> tag "Birmingham Items" and then listing all the items returned impossible. 

  6. I'm sorry Larry I'm not explaining this well.

     

    Perhaps this may help:

     

    I have an area table like this:

     

     

    id

    area

    date_added

     

    I have an items table like this:

     

    id

    title

    description

    user_id  (FK To user table)

    area_id (FK to area table)

    date_added

     

    It stores items, so a row might be:

     

    id = 1

    title = red widget

    description = a description of the widget

    user = 32

    area_id = 3

    date_added = 2013-01-12 17:09:19

     

    If i were to load an area page so localhost/location/3/birmingham

     

    I want it to load all records in the item table that have a FK that equates to birmingham.

     

    So it's like finding all the items that are for sale in a particular geographical area.

     

    Does that help at all. 

     

    EDIT:

     

    So

     

    $model[$id]['area'] // relates to the area.
    

    and

     

    $model[$id]['areaItems'] // relates to the items for that area
    
    

    areaItems is a relation in my Area Model: 

     

    'areaItems' => array(self::HAS_MANY, 'Items', 'area_id'),
    
  7. Thanks Larry + Edward

     

    I ended up moving the code out of SiteController and into the Category model for better separation of code. I would much prefer to use DAO on a whole because I like being able to use SQL. It's a bit harder to use AR with more complicated queries i find, but i suppose that's to be expected with anything new. But the added security and a couple of other things are nice the other methods provide.

     

    Thanks for your help

     

    Jonathon 

  8. Hi Larry

     

    I did start with that.

     

    <?php echo CHtml::encode($model[0]->area); ?>
    

     

    But that will always print the 1st area from the DB won't it? It seems to.

     

    In the area table if the records are like this:

     

    1 London

    2 Manchester

    3 Birmingham

    // more areas

     

    so the url:

    localhost/location/2/manchester

    localhost/location/3/birmingham

     

    would still print <h1>London Items</h1> when using <?php echo CHtml::encode($model[0]->area); ?>. Because $model[0]->area will always be the first area in the DB (London). 

     

    So I needed a way to dynamically print the <h1> tag depending on what value was used in the url.

     

    If I passed back the $id unadjusted for manchester area items. Then the $id would be 2. 

     

    <h1><?php echo CHtml::encode($model[$id]['areaItems']); ?> Items</h1>
    

     

    Then it would print the 3rd area's title (Birmingham) and the result set would also be that of Birmingham's, not Manchester's.

     

    The variable isn't altered from what is provided in the url when accessing the controller or model. So my (flawed) logic was get all the correct records for each area. Then provide an adjusted variable to pass back to the view so you can align the php array with the mysql record so you can correctly print the area's <h1> tag and loop through the returned results?

  9. Apologies Larry, I should have posted more code

     

    My route is

     

     
                    'location/<id:\d+>/<slug:[a-z-]+>' => 'area/index', // url for creating location/1/area-name
     
    

     

    My Model

     

     
        public function returnItemsInArea($id){
                 
            $model = Item::model()->with('areaItems')->findAll($id);
            
            return $model;
     
        }
     
    

     

    My Controller

     

     public function actionIndex($id)
        {
           
        $items = Item::model()->returnItemsInArea($id);
        $recordCounter = (int)$id -1;
       
            $this->render('index', array(
            'model'=>$items,
            'id'=>$recordCounter
            ));
        }
    
    

    My thinking was that localhost/location/1/area-name would be a way to select all the items in a particular area by passing the id of area in the url. The id in the url is mentioned in the route, I take that in the controller and pass it to the model to query the DB. But with it returning an array of objects I needed a way to select the correct object dynamically. This seemed like a way to do it. Although I wasn't sure if this was acceptable to do or how it could be done better.

  10. This I suppose isn't strictly for the Yii book. But I'm doing it through Yii.

     

    I did build all my queries in Query Builder. Which has been fine I must admit, But I had a couple of glitches. For instance, I had been using a simple foreach($model as $row) to access through my records. The problem came when I wanted to give the <h1> on the page a better description. As far as I could see the only way was to access the $model was through a foreach loop. Which worked, but then when I came to echo out the majority of the data I got a "Couldn't rewind" error. Because i'd tried to use $model in another foreach loop - Do tell me if there is an easy fix to this though.

     

    So, to cut a long story short, I thought I'd move back to AR and try to get these queries working. It's basically returning an array of objects. Which took me a while to get. I just wanted to check on something. My route, just uses the $id from the the URL, that's passed to the model and the data is returned as a $model to the controller which passes it on to my view. My question is regarding the passing of variables back to the view. 

     

    Is it ok just to do this:

     

     
        public function actionIndex($id)
        {
            
        $items = Item::model()->returnItemsInArea($id);
        $recordCounter = (int)$id -1;
        
            $this->render('index', array(
            'model'=>$items,
            'id'=>$recordCounter
            ));
        }
     
    

     

    Is that ok? I just pass back the $id variable (-1 to fall inline with the array indexes) to help select the correct model. So in my view

     

    <h1><?php echo CHtml::encode($model[$id]['Area']); ?> Items</h1> // Displays the correct area
    

     

    I then use it in a similar fashion to check that the $model isn't empty and then if not it returns a list of items. It seems to work correctly. But I wanted to check. I know Edward mentioned to me that it was a pain to access.

     

     
    if(!empty($model[$id]['areaItems'])){
        
        foreach($model[$id]['areaItems'] as $row){
     
            echo '<h4>' . $row['title'] . '</h4>';
            // More data to output
        }
    } else {
        echo 'No Items';
    }
     
    
  11. So if I am going to move the SQL to a model. Which model as it's for the index page? I'm not sure then how to pass it along to the site/index controller/view.

     

    Inside SomeModel.php

     

    public function returnSomeResults()
    {
    
    $cmd = Yii::app()->db->createCommand();
    $cmd->select(array('c.name, COUNT(i.category_id) as numItems'));
    $cmd->from('category as c');
    $cmd->leftJoin('item as i', 'c.id=i.category_id');
    $cmd->group('c.name');
    $cmd->order('c.name', 'ASC');
    $result = $cmd->query();
    
    return $model;
    }
    

     

    Then inside Controller.php

     

    how would you then go about passing the model to view?

    
    public function actionIndex()
    {
    
    
    $model = SomeModel::model()->returnSomeResults();
    
    $this->render('index',array(
    'model'=>$model,
    ));
    }
    

     

    Like that?

     

    That seems to give me a workable $model in my view that I can use a foreach lop to print data.

  12. Ok, I've made some progress with this. But wanted to know if I was going about things the right way. My controller code hasn't changed. Just in my view I have

     

    
    <?php foreach($model as $row){
    
    echo '<li><a>' . $row['name'] . '</a><span class="muted"> ' . $row['numItems'] . '</span></li>';
    }
    ?>
    

     

    Seems to output what I wanted. But the main thing for me is that things are going in the right places and the better practices are being used. If someone can just let me know that would be great. :)

  13. Hi Larry,

     

    I'm going to use the following query

    
    
    select c.name, count(i.category_id)
    from category as c left outer join
    item as i
    on c.id = i.category_id
    group by c.name
    order by c.name ASC
    
    

     

    What would be you preferred method for interacting with the database here?

     

    I wrote this:

     

    
    $cmd = Yii::app()->db->createCommand();
    $cmd->select(array('c.name, COUNT(i.category_id) as numItems'));
    $cmd->from('category as c');
    $cmd->leftJoin('item as i', 'c.id=i.category_id');
    $cmd->group('c.name');
    $cmd->order('c.name', 'ASC');
    $result = $cmd->query();
    

     

    This is for use on my index page.

     

    Is it correct to place for this code within my SiteController.php???

     

    public function actionIndex()
    {
    
    $this->layout = '//layouts/home'; // uses the home layout for index page
    
    
    $cmd = Yii::app()->db->createCommand();
    $cmd->select(array('c.name, COUNT(i.category_id) as numItems'));
    $cmd->from('category as c');
    $cmd->leftJoin('item as i', 'c.id=i.category_id');
    $cmd->group('c.name');
    $cmd->order('c.name', 'ASC');
    
    $model = $cmd->query();
    
    // render index view
    $this->render('index',array(
    'model'=>$model
    ));
    
    

     

    I wasn't sure how to pass the object to the view. I got the impression from the book that it doesn't return usable objects. I used

    print_r($model);
    

     

    in my index.php view and it returned a CDbDataReader Object which I expected. But not much else. I know when I made a really simple AR query and passed the model off to the view it returned a lot more info. So i'm questioning a few things.

     

    1) Am I using the wrong DB method. (This one seemed easier for me to comprehend when constructing an aggregated SQL query).

    Perhaps I should just use DAO as none of the information is generated from user information.

     

    2) Am I placing the code for the SQL in the right place (SiteController.php)

     

    3) Am I passing the information to the view correctly.

  14. Hey Larry,

     

    I just left it as

    'item/<id:\d+>/<title>' => 'item/view',

     

    Which currently was ok, as I was just experimenting. However, I wasn't sure why

     

    'item/<id:\d+>/<title:\^[a-zA-Z-]+>' => 'item/view',

     

    wasn't working. If you could let me know if there are any obvious errors with this that would be great as i'd prefer to use a regex to monitor what's in the url. That being said, i'll refer back to my last comment. As i'm purely using the title for decoration purposes, do I even need the regex as nothing in the url is using within the controller?

     

    Thanks for getting back to me

    • Upvote 1
  15. XHTML is still very much in use. You can feasibly use either, but there's a strong argument for using HTML5 currently. They are very similar at a base level so for the book it doesn't make much difference as the book is about PHP. It would be easier to just follow the book and it's (presumably) XHTML I suspect as it's about PHP. But if you could always do some light reading around HTML5. I always liked w3schools for intros, i've never read this piece but it may be of some use to you as a side project.

     

    http://www.w3schools.com/html/html5_intro.asp

  16. So,

     

    I used this rule in my config

    'item/<id:\d+>/<title>' => 'item/view',

     

    Which works. The title placeholder accepts any characters. I am purely using this rule for user readability. Is that approach ok? I would assume so purely because the actionView() only accepts the $id. However if somebody could confirm this for me that would be great.

     

    I'm still a little unsure why when i try

     

    <title:\^[a-zA-Z-]+>
    

     

    It fails

    • Upvote 1
×
×
  • Create New...