Tiger_Model_User

@api · extends Tiger_Model_Table

User — a person / identity. Deliberately THIN.

A User row is PURE IDENTITY: id, email, optional username, and status. That's it. NO credentials, NO profile, NO org, NO role — none of those belong on the user:

  • CREDENTIALS (password, SMS/phone, TOTP, passkeys, SSO) live in user_credential (Tiger_Model_UserCredential), 1-to-many, because auth is multi-factor and a credential is not identity.
  • Profile/richness (name, avatar, phone-as-contact, preferences) belongs to an Account MODULE that extends User via its own FK-linked table, so the platform updates without colliding with app-specific profile shapes.
  • A user's relationship to a tenant — and their ROLE — lives on org_user (Tiger_Model_OrgUser), because a user can belong to many orgs with a different role in each. A role on the user would force one global role and break multi-tenancy.

Methods

findByEmail()

findByEmail($email)

Find a user by email (the canonical login identifier; unique).

  • $email string

Returns Zend_Db_Table_Row_Abstract|null

findByIdentifier()

findByIdentifier($identifier)

Resolve a login IDENTIFIER to a user — the one entry point every login flow uses. An identifier is what you claim to be; the CREDENTIAL (password / code / passkey) that proves it is verified separately, afterward.

Resolution order, first hit wins:

  1. email — the canonical identity column (unique)
  2. username — identity column (unique)
  3. a verified factor identifier in user_credential — the (type, identifier) reverse-lookup the schema was built for: phone (sms, E.164), oauth subject, webauthn cred-id. Singleton factors (password/totp) carry identifier='' and never match here, and a pending/unverified factor must not resolve identity.

Email-first keeps things deterministic if a username ever equals another user's email local-part. Phone/oauth/passkey login all fall out of step 3 for free once those factors exist (phone-number normalization lands with the SMS factor).

  • $identifier string — email | username | a verified factor identifier

Returns Zend_Db_Table_Row_Abstract|null

datatable()

datatable(array $opts)

DataTables data for the Users admin: identity + a membership summary (org count and the distinct roles held, via org_user). Owns the query; the service handles presentation + ACL. Returns total (scoped), filtered (scoped + search), and one page of rows.

  • $opts array

Returns array{total:int,filtered:int,rows:array}

isTaken()

isTaken($col, $value, $excludeId = null)

Is $value already used in $col (email|username) by a different, non-deleted user?

  • $col string — the column to check — 'email' or 'username'
  • $value string — the value to test for uniqueness
  • $excludeId string|null — a user_id to exclude (the row being edited)

Returns bool — true if the value is already taken by another user