EzDevInfo.com

Ardent

A Collections library for PHP.

Ardent + Laravel, auto hydrate relation

I use lavarel with ardent package.

I have some problem when i want to update a row.

I have 2 model Client and Address related by morphone relation.

This relation work well, when i want to get a client this line return expected result :

Client::with('address')->find($id);

But i can't understand how to update a client with a clean solution. Somebody can answer to these questions :

  1. With Ardent how could you autoHydrate related model ?
  2. When you update some data, what is the best practice in lavarel ? Use update methdod ? Use save ? Use push ? Fill all model ? Use auto hydrate ?

When i log Input::all() in my update method i get that :

[2014-05-31 15:52:56] production.INFO: {"id":983,"firstName":"Susanne","lastName":"Adam","birthDate":"18\/06\/1982","inscriptionDate":"08\/09\/2013","status":3,"created_at":"2014-05-31 14:26:25","updated_at":"2014-05-31 14:26:25","email":"bernard.alix@free.fr","address":{"id":983,"address":"avenue Etienne","address2":"","ville":"Cordierboeuf","cp":"25 10","phone":"0403983157","mobile":"+33 (0)3 0","addressable_id":983,"addressable_type":"Client","created_at":"2014-05-31 14:27:58","updated_at":"2014-05-31 14:27:58"}} [] []

As you see address data are inside client data.

3.When I use update, save or push (eloquent's method) eloquent does not understand that he should update Address model then update related Client model. My data's format isn't well formed ?

Thanks.

UPDATE :

When i do Log::info(Input::all()), i get the following json data in my controller :

[2014-06-01 18:10:46] production.INFO: {"id":284,"firstName":"Andr\u00e9e","lastName":"Adam","birthDate":"23\/07\/1944","inscriptionDate":"22\/11\/2013","status":2,"created_at":"2014-06-01 15:41:22","updated_at":"2014-06-01 18:06:44","email":"monique17@normand.com","address":{"id":284,"streetAddress":"93, avenue Lefort","streetAddress2":"","city":"Boulay-sur-Leger","zipCode":"14054","phone":"09 51 03 1","mobile":"+33 6 00 6","addressable_id":284,"addressable_type":"Client","created_at":"2014-06-01 15:42:50","updated_at":"2014-06-01 18:06:44"}} [] []

With ardent's autohydratation that doesn't work... Client autohydrate successfully but Address does not, maybe due to the polymorphic relation (one-to-one) between them.

I try to fill my models this way :

$client = Client::with('address')->find($id);
$client->update(Input::except('address'));
$client->address->update(Input::only('address'));

but this doesn't work because Input::only('address') gives wrong formed data, when i log this i get that :

Log::info(Input::except('address'));
Log::info(Input::only('address'));

//output 

[2014-06-01 18:20:34] production.INFO: {"id":284,"firstName":"Andr\u00e9e","lastName":"Adam","birthDate":"23\/07\/1944","inscriptionDate":"22\/11\/2013","status":2,"created_at":"2014-06-01 15:41:22","updated_at":"2014-06-01 18:10:46","email":"monique17@normand.com"} [] []
[2014-06-01 18:20:34] production.INFO: {"address":{"id":284,"streetAddress":"93, avenue Lefort","streetAddress2":"","city":"Boulay-sur-Leger","zipCode":"14054","phone":"09 51 03 1","mobile":"+33 6 00 6","addressable_id":284,"addressable_type":"Client","created_at":"2014-06-01 15:42:50","updated_at":"2014-06-01 18:06:44"}} [] []

So i mix two methods :

$inputs = Input::except('_method');
$client = Client::with('address')->find($id);

$client->update(Input::except('address'));
$client->address->update($inputs['address']);

This work pretty well !

But i can't understand why ardent's autohydration fails...

Thanks.


Source: (StackOverflow)

Laravel 'Form::model' does not populate my edit form

I am in the progress of making a form to edit an existing entry in the database. I am using the Form::model approach to do this, however it doesn't seem to work. The fields just stay empty.

ServerController.php

/**
* Editing servers
*/
public function edit($name)
{
  $server = Server::find($name);
  $keywords = ($server->getKeywords()) ? $server->getKeywords() : array();
  $countries = $this->getCountries();
  return View::make('server/edit', array('server' => $server, 'countries' => $countries));
}

public function update($name) 
{
  $server = Server::find($name);
  // Did it succeed?
  if($server->save()) {
    Session::flash('success', 'You server was edited!');
    return Redirect::route('server.view', array($name));
  }

  // Did not validate
  if(Input::get('keywords')) {
    $keywords = Input::get('keywords');
    Session::flash('keywords', $keywords);
  }
  Session::flash('danger', "<b>Oops! There were some problems processing your update</b><br/>" . implode("<br/>", $server->errors()->all()));
  return Redirect::route('server.edit', array($name))->withInput()->withErrors($server->errors());
}

The Form

{{ Form::model($server, array('route' => array('server.update', $server->name), 'class' => 'form-horizontal', 'role' => 'form', 'files' => true)) }}
  <div class="form-group {{ $errors->has('email') ? 'has-error' : '' }}">
    {{ Form::label('email', 'Email', array('class' => 'control-label col-md-4')) }}
    <div class="col-md-4">
      {{ Form::text('email', '', array('class' => 'form-control')) }}
      {{ $errors->first('email', '<br/><div class="alert alert-danger">:message</div>') }}
    </div>
  </div>
  (some more fields)
{{ Form::close() }}

Source: (StackOverflow)

Advertisements

Laravel 4 Ardent beforeSave() and $this->changed()

I'm running though the Laravel 4 Ardent package found here: https://github.com/laravelbook/ardent

I'm trying to integrate the code found in Ardent's README within my User Model:

public function beforeSave( $forced )
{
    // if there's a new password, hash it
    if($this->changed('password'))
    {
        $this->password = Hash::make($this->password);
    }

    return true;
}

My User Model Test:

public function testSetPassword() 
{
    // Create a new User
    $user = new User;
    $user->email = "joe@smalls.com";
    $user->password = "password";
    $user->password_confirmation = "password";
    $user->save();

    /* Test #1 - Test to make sure password is being hashed */
    $this->assertTrue(Hash::check('password', $user->password), "the set_password() function did not return TRUE");
}

When I test via PhpUnit, it is telling me that '$this->changed()' is undefined.

BadMethodCallException: Call to undefined method Illuminate\Database\Query\Builder::changed()

I'm basically trying to do as the tutorial says, and check to make sure the password has changed before saving it to the DB. Any help would be greatly appreciated.


Source: (StackOverflow)

Laravel/Ardent: Is there a simpler way to do custom error messages?

Is there a simpler way to use custom validation error messages in Laravel rather than listing each field and attribute in an array? I don't mind the typing, I just feel it looks rather dirty.

Here is my two blocks of code now...

public static $rules = array(
    'first_name' => 'required|alpha',
    'last_name' => 'required|alpha',
    'email' => 'required|email',
    'password' => 'required|alpha_num|min:8|confirmed',
    'password_confirmation' => 'required|alpha_num'
);

public static $messages = array(
    'first_name.required' => 'You must enter your First Name!',
    'first_name.alpha' => 'Your first name must contain alphabetical characters only!',
    '...and so on' => 'for the rest...'
);

in the public static $messages block, I'm wondering if there's any way I can clean that up without typing each field name and attribute? Can I, for example, do something like this instead?

public static $messages = array(
    'first_name' => array(
         'required' => 'msg',
         'alpha' => 'msg'
     ),
     'and so on' => array(
         'for the' => 'rest'
     )
);

To me, that seems cleaner. Thanks for any input you can provide.


Source: (StackOverflow)

Ardent password_confirmation error

I'm using ardent to validate my User model but for some reason it's always returning the two following errors:

  • The password confirmation does not match.
  • The password confirmation field is required.

I've been stumped on the one for a while so any help is appreciated. Guessing it has do to with my setup or Ardent but can't figure it out. My unit tests are passing the follow test route also passes:

Route::get('testuser', function() {
    $user                        = new User;
    $user->first_name            = 'John';
    $user->last_name             = 'Doe';
    $user->birthday              = '11/11/11/';
    $user->email                 = 'johndoe@gmail.com';
    $user->password              = 'password';
    $user->password_confirmation = 'password';

    var_dump($user->save());
});

I'm not creating the user this way on form submit though. My controller action looks like this:

$user = $this->user->create(Input::all());

if ($user->save()) {
     return Redirect::route('users.index')
          ->with('flash', 'The new user has been created');
}

return Redirect::route('register.index')
     ->withInput()
     ->withErrors($user->errors());

With the Input::all() array equalling:

array (
  '_token' => 'removed',
  'first_name' => 'John',
  'last_name' => 'Doe',
  'birthday' => '11/11/11',
  'email' => 'johndoe@gmail.com',
  'password' => 'password',
  'password_confirmation' => 'password',
)

And finally my User model is set up like so:

class User extends Ardent implements UserInterface, RemindableInterface {

    protected $table                     = 'users';

    protected $hidden                    = array();

    protected $fillable                  = array(
        'email',
        'first_name',
        'last_name',
        'birthday',
        'password',
        'password_confirmation'
    );

    protected $guarded                   = array('id');

    public static $passwordAttributes    = array('password');

    public $autoPurgeRedundantAttributes = true;

    public $autoHydrateEntityFromInput   = false;

    public static $rules = array(
        'email'                 => 'required|email|unique:users',
        'first_name'            => 'required',
        'last_name'             => 'required',
        'birthday'              => 'required',
        'password'              => 'required|alpha_num|min:6|confirmed',
        'password_confirmation' => 'required|alpha_num|min:8',
    );

Source: (StackOverflow)

Getting a throwOnFind: false response from Ardent in Laravel

I'm trying to perform an .ajax get to populate a table using Knockout/Jquery in Laravel 4. I use Ardent and it keeps responding with the following json response.

{"throwOnFind":false}

Controller:

    public function getData()
{
    $roles = Role::select(array('roles.id',  'roles.name', 'roles.id as users', 'roles.created_at'));
    return Response::json($roles, 200, array('Content-Type' => 'application/json'));
}

JavaScript:

function Role(data) {
    this.id = ko.observable(data.id);
    this.name = ko.observable(data.name);
    this.users = ko.observable(data.users);
    this.created_at = ko.observable(data.created_at);
}
function ViewModel() {
    var self = this;
    self.roles = ko.observableArray([]);
    $.ajax({
        type: "GET",
        url: "{{ URL::to('admin/roles/data') }}",
        complete: function(allData) {
            var mappedRoles = $.map(allData, function(item) {
                return new Role(item);
            });
        }
    }, "json");

    self.roles(mappedRoles);
}

ko.applyBindings(new ViewModel());

I don't really know where to go from here. I think the problem may be in Ardent.


Source: (StackOverflow)

Having trouble getting fields to validate with Laravel / Ardent

I'm new to Laravel and am trying to figure out how to validate user input.

I have a form with several text fields, a textarea and a checkbox:

      {{ Form::text('firstname', '', ['placeholder' => 'First Name', 'class' => 'form-control']) }}
      {{ Form::text('lastname', '', ['placeholder' => 'Last Name', 'class' => 'form-control']) }}
      {{ Form::email('email', '', ['placeholder' => 'Email', 'class' => 'form-control']) }}
      {{ Form::textarea('question', '', ['placeholder' => 'Question', 'class' => 'form-control']) }}
      {{ Form::checkbox('terms_and_conditions', 'yes') }}
      {{ Form::label('terms_and_conditions', 'I agree to terms and conditions') }}

The validation rules are:

  public static $rules = array(
    'firstname' => 'required|between:2,20',
    'lastname' => 'required|between: 2,30',
    'email' => 'required|email',
    'question' => 'required|max: 5000',
    'terms_and_conditions' => 'required|accepted',
  );

The text fields are all validating as expected, but I cannot get the checkbox field to validate. I echoed the json of $input to the view and can verify that the model is receiving the terms_and_conditions checkbox value, so I don't understand why it won't validate?

If I add any new fields or change a field's name those fields won't validate as well.

Am I missing something?


Source: (StackOverflow)

Laravel Ardent not letting me save my User

I started a project last night in Laravel and am using Ardent and Entrust packages to help make my User model more secure and easy to use. I have set everything up but am not able to seed my database. No errors are thrown but it is definitely not saving to my database.

This is my User model.

<?php

use Illuminate\Auth\UserInterface;
use Illuminate\Auth\Reminders\RemindableInterface;
use LaravelBook\Ardent\Ardent;
use Zizaco\Entrust\HasRole;

class User extends Ardent implements UserInterface, RemindableInterface {
    use HasRole;

    public static $rules = array(
        'username'              => 'required|alpha_num|between:6,18|unique:users',
        'email'                 => 'required|email|unique:users',
        'password'              => 'required|alpha_num|min:8',
        'password_confirmation' => 'required|alpha_num|min:8',
        'first_name'            => 'alpha',
        'last_name'             => 'alpha',
        'city'                  => 'alpha',
        'state'                 => 'alpha',
        'rate'                  => 'numeric',
        'profile_pic'           => 'image',
        'commitment'            => 'string'
    );

    public static $passwordAttributes  = array('password');

    public $autoHydrateEntityFromInput = true;

    public $forceEntityHydrationFromInput = true;

    public $autoPurgeRedundantAttributes = true;

    public $autoHashPasswordAttributes = true;

    protected $table = 'users';

    protected $hidden = array('password');

    public function getAuthIdentifier()
    {
        return $this->getKey();
    }

    public function getAuthPassword()
    {
        return $this->password;
    }

    public function getReminderEmail()
    {
        return $this->email;
    }

}

This is my users schema in my migrations.

Schema::create(
    'users',
    function (Blueprint $table) {
        $table->increments('id');
        $table->string('username');
        $table->string('email');
        $table->string('password', 60);
        $table->string('first_name')->nullable();
        $table->string('last_name')->nullable();
        $table->string('city')->nullable();
        $table->string('state', 2)->nullable();
        $table->string('zip', 9)->nullable();
        $table->float('rate', 10, 2)->nullable();
        $table->boolean('listed')->default(false);
        $table->string('profile_pic')->nullable();
        $table->string('commitment')->nullable();
        $table->timestamps();
        $table->softDeletes();
    }
);

Lastly, here is my seed data.

$admin = User::create(
    array(
         'username'              => 'admin',
         'email'                 => 'admin@example.com',
         'password'              => 'admin',
         'password_confirmation' => 'admin',
         'first_name'            => 'Admin',
         'last_name'             => 'User',
         'city'                  => 'Cincinnati',
         'state'                 => 'OH',
         'zip'                   => '45243'
    )
);

User::create(
    array(
         'username'              => 'user',
         'email'                 => 'user@example.com',
         'password'              => 'user',
         'password_confirmation' => 'user',
         'first_name'            => 'Normal',
         'last_name'             => 'User'
    )
);

I have narrowed it down to the fact that I'm extending Ardent in my User model, but I don't know why.


Source: (StackOverflow)

Fillable list ignored while inserting related model

I am using Ardent and I faced strange behaviour of ignoring $fillable list while inserting/updating related models. I have the following models defined:

class User extends LaravelBook\Ardent\Ardent
{
    protected $table = 'users';

    public static $relationsData = [
        'contacts' => [self::HAS_MANY, 'Contact'],
    ];    
}

class Contact extends LaravelBook\Ardent\Ardent 
{
    protected $table    = 'user_contacts';
    protected $guarded  = ['*'];
    protected $fillable = [
        'user_id',
        'type',
        'value'
    ];

    public static $relationsData = [
         'user' => [self::BELONGS_TO, 'User'],
    ];
}

Now I am trying to add new contact to user:

    $user->contacts()->create([
    'type' => 'some type',
    'value' => 'some value',
    'unknown_field' => 'unknown value'
]);

... and I got SQL insert error:

SQLSTATE[42S22]: Column not found: 1054 Unknown column 'unknown_field' in 'field list'     (SQL: insert into `user_contacts` (`type`, `value`, `unknown_field`, `user_id`, `updated_at`, `created_at`) values (?, ?, ?, ?, ?, ?)) (Bindings: array ( 0 => 'some type', 1 => 'some value', 2 => 'unknown value', 3 => 2, 4 => '1384854899', 5 => '1384854899', ))

In the same time this is working fine:

UserContact::create([
    'user_id'       => 2,
    'type'          => 'some type',
    'value'         => 'some value',
    'unknown_field' => 'unknown value'
]); 

I didn't get any SQL errors and 'unknown_field' was just ignored.

Any ideas why $fillable fields could be ignored while working via builder?!


Source: (StackOverflow)

Make Ardent in Laravel not requiring new password on save

I'm doing user editing facility for my admin panel. I want to ignore empty password on update, but not on create.

I have following validation rules for User model:

public static $rules = array(
    'login'                 => 'required|max:255|alpha_dash|unique',
    'displayname'           => 'required|max:255|unique',
    'email'                 => 'required|email|max:255|unique',
    'password'              => 'required|confirmed',
    'password_confirmation' => 'required',
);

But it doesn't let me update user model when I don't pass password to it. It just complains about not having a password.

How to make it work?


Source: (StackOverflow)

Laravelbook/Ardent ignoring autoHydrateEntityFromInput value

I have $autoHydrateEntityFromInput = true and $forceEntityHydrationFromInput = false because I want the input elements not in the model rules to be dropped during hydration. If they aren't dropped, there is a "column not found" error for the model on update because some of the form fields are supplemental.

However, when these two settings are used in this way, Ardent will not update any of the fields. It will only update fields when $forceEntityHydrationFromInput = true, which does not appear to be the functionality described in the documentation.

Am I wrong? If so, how do I get the fields auto-hydrated while excluding any not found in the rules?

I can use Ardent::$purgeFilters to specifically exclude each supplemental field that isn't in the model, but that seems like it should be unnecessary given the documented functionality for auto-hydration.


Source: (StackOverflow)

Validate two models in Laravel 4.2

I have a form that represents two instances of a same Address class (let's say main address and billing address), which in turn inherits from Ardent.

The form is defined as:

Form::model($data, ...)

where:

$data = [ 'mainAddress' => [instance A of Address], 
          'billingAddress' => [instance B of Address] ];

The fields in the form have names that follow an array notation, such as:

Form::text('mainAddress[zipcode]')
...
Form::text('billingAddress[zipcode')

in order to pull out both models with ease with Input::get('mainAddress') and Input::get('billingAddress').

I have some problems to find a concise way to check the validation errors for both the models. Checking both the instances is no big deal, the problem is in the view where I must display the appropriate error next to the field; in normal cases I'd use a simple $errors->has('fieldName'), but with two instances I have problems in pulling out with ease the error message.

Note: I know that a solution would be to flatten the field names (f.ex. mainAddress_zipcode) and define a custom ruleset that comprises the fields of both the instances, but it seems likely that I'm missing a more concise and elegant way to do this.


Source: (StackOverflow)

Is it necessary to test relationships in both directions?

I'm attempting to test relationships between models using Ardent and FactoryMuff. I'm able to test the relationship in the belongs_to direction, but I'm having trouble testing it in the has_many direction.

The models I'm testing are a residential real estate rental application and it's corresponding rental history. A very simplified db schema:

+--------------+
| applications |
+--------------+
| id           |
| name         |
| birthday     |
| income       |
+--------------+

+----------------+
| history        |
+----------------+
| id             |
| application_id |
| address        |
| rent           |
+----------------+

This is my history model:

class History extends Ardent
{
    protected $table = 'history';

    public static $factory = array(
        'application_id' => 'factory|Application',
        'address' => 'string',
        'rent' => 'string',
    );

    public function application()
    {
        return $this->belongsTo('Application');
    }
}

This is my test to make sure that a history object belongs to a rental application:

class HistoryTest extends TestCase
{
    public function testRelationWithApplication()
    {
        // create a test rental history object
        $history = FactoryMuff::create('History');

        // make sure the foreign key matches the primary key
        $this->assertEquals($history->application_id, $history->application->id);
    }

}

This works just fine. However, I can't figure out how to test the relationship in the other direction. In the project requirements, a rental application MUST have at least one rental history object associated with it. This is my application model:

class Application extends Ardent
{
    public static $rules = array(
        'name' => 'string',
        'birthday' => 'call|makeDate',
        'income' => 'string',
    );

    public function history()
    {
        return $this->hasMany('History');
    }

    public static function makeDate()
    {
        $faker = \Faker\Factory::create();
        return $faker->date;
    }
}

This is how I'm attempting to test the has_many relationship:

class ApplicationTest extends TestCase
{
    public function testRelationWithHistory()
    {
        // create a test rental application object
        $application = FactoryMuff::create('Application');

        // make sure the foreign key matches the primary key
        $this->assertEquals($application->id, $application->history->application_id);
    }
}

This results in ErrorException: Undefined property: Illuminate\Database\Eloquent\Collection::$application_id when I run my unit tests. It makes sense to me. Nowhere have I told FactoryMuff to create at least one corresponding History object to go along with my Application object. Nor have I written any code to enforce the requirement that an Application object must have at least one History object.

Questions

  1. How do I enforce the rule "an application object MUST have at least one history object"?
  2. How do I test the has_many direction of the relationship?

Source: (StackOverflow)

Creating a custom validation rule in Ardent w/ Laravel that can access the model to do dirty checking

Goal

I have an Ardent model called User in Laravel.
I want to have a custom validation rule called confirm_if_dirty.

This would only run if the User->password attribute is dirty. It would expect there to be a User->password_confirmation field.

Below is an example of how this rule might look.

Validator::extend('confirm_dirty', function($attribute, $value, $parameters) use($model)   
{
//If field is not dirty, no need to confirm.
if($model->isDirty("{$attribute}")){

    //Confirmation field should be present.
    if(!$model->__isset($attribute."_confirmation")){
        return false;
    }
    //Values should match.
    $confirmedAttribute = $model->getAttribute($attribute."_confirmation");
    if( $confirmedAttribute !== $value){
        return false;
    }
    //Check to see if _confirmation field matches dirty field.
}

return true;

});

Question

How can I make it so that $model in my case is passed in or is the model instance in question?


Source: (StackOverflow)

Laravel Ardent not saving model when using updateUniques()

I'm doing user editing facility for my admin panel. I'm using updateUniques() in my code, as recommended by Ardent when having 'unique' rules in the model.

When I do it, it passes with no problem, but model hasn't changed.

My code:

$user = User::findOrFail($id);

if ($user->exists)
{
    $user::$rules['password'] = (Input::get('password')) ? 'required|confirmed' : '';
    $user::$rules['password_confirmation'] = (Input::get('password')) ? 'required' : '';
}

if ($user->updateUniques())
{
    Session::flash('successes', array_merge((array) Session::get('successes'), ['Pomyślnie zmieniono użytkownika']));
    return Redirect::route('users.show', ['users'   =>  $user->id]);
}
else
{
    return Redirect::route('users.edit', ['users'   =>  $user->id])
    ->withErrors($user->errors())
    ->withInput(Input::except('password'));
}

Source: (StackOverflow)