We have moved our forum to GitHub Discussions. For questions about Phalcon v3/v4/v5 you can visit here and for Phalcon v6 here.

Ajax save model

Hi,

When i'm trying to save my model like this if( !$myModel->save() ) I have to surround in try catch my condition if I want to get the errors messages... I can't check if the save() is false, because this will not returns the errors.

How can I do to get $myModels->getMessages() without using try catch ?

I want to do like this example.

Can you post your model? I think you you're missing some validation or relation.

edited May '16

I don't have validations in my model :/ But relations are ok. Actually the errors is that I sent bad datetime format but I seen this error with a try catch. I can't return json_encode because there is a crash on my condition if I remove my try catch.



3.3k
Accepted
answer

This thread could be useful then.

Ok so I have to implement all validations.

I'll do that, thanks.

I actually created exception. When save/create/delete can't happen for some reason i throw it and it returns reponse with error messages and then value for dispatcher in beforeException is setted for this response and dispatch loop is executed - this way i have returned response with error messages(in json in my case) and i don't have to have additional boilerplate code in every app.

Well another way can be to throw this exception even in save/create/delete etc of model method if it fails.

Wojciech Ślawski could you give me a code snippet for this please ?

I actually created exception. When save/create/delete can't happen for some reason i throw it and it returns reponse with error messages and then value for dispatcher in beforeException is setted for this response and dispatch loop is executed - this way i have returned response with error messages(in json in my case) and i don't have to have additional boilerplate code in every app.

Well another way can be to throw this exception even in save/create/delete etc of model method if it fails.

edited May '16

Hmm, fine, this is exception for example:

<?php
/**
 * Created by PhpStorm.
 * User: User
 * Date: 12.05.16
 * Time: 15:35
 */
namespace Suzuki\App\Exceptions;

use Exception;
use Phalcon\Di;
use Phalcon\Http\Request;
use Phalcon\Http\Response;
use Phalcon\Mvc\Model;
use Phalcon\Mvc\Model\Message;
use Phalcon\Queue\Beanstalk;
use Suzuki\App\Interfaces\ResponseExceptionInterface;

class ModelException extends Exception implements ResponseExceptionInterface
{
    /**
     * @var Model
     */
    protected $model;

    /**
     * @var array
     */
    protected $messages;

    /**
     * @param string $message
     * @param int $code
     * @param Exception|null $previous
     * @param Model $model
     */
    public function __construct($message, $code = 0, Exception $previous = null, Model $model)
    {
        parent::__construct($message, $code, $previous);
        $this->model = $model;
        $di = Di::getDefault();
        $dispatcher = $di->get('dispatcher');
        /** @var Beanstalk $queueLog */
        $queueLog = $di->get('queue');
        $queueLog->choose('log');
        $queueLog->put([
            'type' => 'modelException',
            'message' => "
                Can't save/delete/update/create model of class " . get_class($model) . " due to certain validation messages:" . PHP_EOL .
                json_encode($this->getMessages()) . PHP_EOL .
                "Model data:" . json_encode($model->toArray()) . PHP_EOL .
                PHP_EOL .
                'URL: ' . $di->get('request')->getURI() . PHP_EOL .
                'Module name:' . $dispatcher->getModuleName() . PHP_EOL .
                'Controller name:' . $dispatcher->getControllerName() . PHP_EOL .
                'Action name:' . $dispatcher->getActionName() . PHP_EOL .
                'Params:' . json_encode($dispatcher->getParams()) . PHP_EOL .
                'POST:' . json_encode($_POST) . PHP_EOL .
                'JSON:' . json_encode($di->get('request')->getJsonRawBody(true)) . PHP_EOL .
                'User id:' . $di->get('session')->get('user') . PHP_EOL .
                'IP:' . $di->get('request')->getClientAddress() . PHP_EOL .
                '============================================================='
        ]);
    }

    private function getMessages()
    {
        if (empty($this->messages)) {
            $messages = [];
            /** @var Message $message */
            foreach ($this->model->getMessages() as $message) {
                $messages += [(string)$message->getField() => $message->getMessage()];
            }
            $this->messages = $messages;
        }
        return $this->messages;
    }

    /**
     * @param string $message
     * @param Model $model
     * @return ModelException
     */
    public static function create($message, $model)
    {
        return new ModelException($message, 0, null, $model);
    }

    /**
     * @return string
     */
    public function __toString()
    {
        return __CLASS__ . ": [{$this->code}]: {$this->message}\n";
    }

    /**
     * @return Response
     */
    public function getResponse()
    {
        $response = new Response();
        $messages = $this->getMessages();
        return $response->setJsonContent(['error' => $this->message, 'result' => $messages]);
    }
}

Then somewhere in code:

if(!$model->save()){
    throw ModelException::create("Can't update model", $model);
}

And in dispatcher(im going to move this to seperated class perhaps):

di->set('dispatcher', function () use ($config, $di) {
    //Create an event manager
    $eventsManager = new Manager();
    //Attach a listener for type "dispatch"
    $eventsManager->attach(
        "dispatch",
        function (Event $event, Dispatcher $dispatcher, Exception $exception) use ($di) {
        // some code
        if($event->getType() == 'beforeException') {
            if($exception instanceof ResponseExceptionInterface) {
                        $dispatcher->setReturnedValue($exception->getResponse());
                        return false;
                    }
            }
        }
    }

Also im using queue to do writing to logs, so it doesn't doing it when returning response.

Thanks man, this is very nice. I like this way

edited May '16

I noticed something. This will not working in my project becaise I can't check if the save() is false as you :

if(!$model->save()){
    throw ModelException::create("Can't update model", $model);
}

My save model is never false because when I have a problem in the save, this will returns Error 500 on this line if(!$model->save()){ and this is the issue of this topic. I don't know why. I tried to put this in my bootstrap file :

\Phalcon\Mvc\Model::setup(array(    
    'notNullValidations' => false
));

But there is no changes.

edited May '16

But what exception you have ? You didn't even post it here. It must be problem somewhere else with your code(like validation method)

I have this :

#0 [internal function]: PDOStatement->execute()\n#1 [internal function]: Phalcon\\Db\\Adapter\\Pdo->executePrepared(Object(PDOStatement), Array, Array)\n#2 [internal function]: Phalcon\\Db\\Adapter\\Pdo->execute('INSERT INTO `cu...', Array, Array)\n#3 [internal function]: Phalcon\\Db\\Adapter->insert('customers', Array, Array, Array)\n#4 [internal function]: Phalcon\\Mvc\\Model->_doLowInsert(Object(Phalcon\\Mvc\\Model\\MetaData\\Memory), Object(Phalcon\\Db\\Adapter\\Pdo\\Mysql), 'customers', 'id')\n#5 Phalcon\\Mvc\\Model->save()\n#6 [internal function]: Apps\\Master\\Controllers\\CustomersController->addAction()\n#7 [internal function]: Phalcon\\Dispatcher->dispatch()\n#8 : Phalcon\\Mvc\\Application->handle()\n#9

SQLSTATE[HY000]: General error: 1366 Incorrect string value: '\\xF0\\x9F\\x98\\x81\\xF0\\x9F...' for column 'firstname' at row 1

It looks like some charset problems maybe ? Show us the rest of code where you setting model(with what)

edited May '16

Yes I have this errors when I put emoji in my form inputs with my smarthphone. I don't have validations in my models, but I thought that the save method returns false if there is any error even the model hasn't validations function. My model looks like this :

<?php
namespace Apps\Common\Models;

use Phalcon\Mvc\Model;

class Customers extends Model {

    public $id;
    public $code;
    public $firstname;
    public $familyname;
    public $email;
    public $archive;
    public $customer_infos;

    public function initialize() {

        $this->hasMany("id", "Apps\Common\Models\Contracts", "id_customer");

        $this->skipAttributes(array("customer_infos"));

    }

    public function afterFetch() {

        $this->customer_infos = $this->firstname." ".$this->familyname.", ".$this->email;

    }

}

In my controller :

$customer = new Customers;
$customer->firstname = $firstname;
$customer->familyname = $familyname;
$customer->email = $email;

if( !$customer->save() ){
    $tools->checkErrors($customer);
    return;
}

checkErrors function :

    public function checkErrors($object){
      $messages = "";

      foreach ($object->getMessages() as $message) {
        $messages .= $message.' -- ';
      };

      error_log('Error DB : '.$messages);
      return;
    }

The checkErrors function isn't call because the save() doesn't return false.

edited May '16

Isn't called beacause you have PDO exception - it can't be inserted. Just fix this exception. I don't know what's doing it - i guess it's about charset in database perhaps ? Tu support emoji in mysql you need to use utf8mb4