Elegant handling of missing data

I have two tables:

  • visits

  • visitors

The visits table saves the id (?r=test/hello&id=abcdef) of everybody who visits my website. Some of the visitors are registered and are therefore within the visitors table. Some are not.

When displaying the visits/details view, I am pulling in the visitor data (name, email etc) from the visitor table. However, when the visitor does not exist (they haven’t registered) I am getting an error:

[b]PHP Notice – yii\base\ErrorException

Trying to get property of non-object[/b]

Instead of an error, I would like to simply display "unknown" in the DetailsView, like this:


link_id     |  visitor_email

=============================

asdiwekgabo |  test@test.com  - this is a registered visitor

lwilsdbiews |  unknown        - this visitor has not registered

Here is my current code:


'model' => $model,

        'attributes' => [

            'id',

            [

                'label' => 'Email',

                'value' => $model->visitor->email,

                'format' => 'email',

            ],

How can I elegantly handle the error when $model->visitor->email does not exist?

Thanks




[

    'label' => 'Email',

    'value' => isset($model->visitor->email) ? $model->visitor->email : null,

    'format' => 'email',

],



You need to check if the value is set or not. Your getting the error because it doesn’t exist.

You don’t show enough code, but if the above doesn’t work, then the ‘visitor’ object doesn’t exist either.




[

    'label' => 'Email',

    'value' => isset($model->visitor) ? $model->visitor->email : null,

    'format' => 'email',

],



if you sometimes get an error because now ‘email’ sometimes isn’t there,




[

    'label' => 'Email',

    'value' => isset($model->visitor, $model->visitor->email) ? $model->visitor->email : null,

    'format' => 'email',

],



Notice, I used null. This would use the default ‘(not set)’ value in Yii’s DetailView and GridView. Just replace it with ‘unknown’ if thats what you want.

i wanted to also add, that I would use relations on your columns (when it makes sense to) instead of storing all the emails or other user info. It will make your db run a lot better when you get a lot of records. This way, you can get whatever info you want later about the user and not have to do yet another query to find the user by that email.

This would be the table structure:




   id   |        link_id        |     user_id

==========================

  1      |   asdiwekgabo  |    37        - this is a registered visitor

  2     |    lwilsdbiews    |   null        - this visitor has not registered



The ‘id’ column would be auto-incrementing ‘int’. The ‘link_id’ a ‘varchar’ of however many you need, say 20. And the ‘user_id’ also an ‘int’ with a foreign key pointing to your ‘user’ table mapped to its ‘id’ column.


Is there a reason you have your table for users named "visitors"? They are a user if they have registered and created an account, no longer "just visiting". Following common naming practices helps others understand your code, and makes it easier on yourself logically.

I also want to point out, that you should use singular table names. ie: ‘user’ instead of ‘users’… or… ‘visit’ instead of ‘visits’… Yii will automatically add an “s” where it needs to… It will also make more sense when you do this:




$visitLog = Visit::find()->all();  // you could tell it to grab all for the past 30 days if you stored the timestamp of the visit


foreach ($visitLog as $visit) {

    echo $visit->user->email;

}



Yii2 Advanced has a migration built in for creating the ‘user’ column for you. It stores the username, email, password, reset hash, token, among other things. It has the baseline of what you need for a user’s database, and stores the user’s passwords using bcrypt (which is the recommended way to save user passwords today). It also has the User model already created for you.

ahhh… brilliant thank you. This is working like a charm.

PS: I am using the visit / visitor structure as an example.

Thanks