{"data":{"markdownRemark":{"frontmatter":{"title":"Транзакции в Laravel","date":"28 September 2018","path":"/tranzaktsii-v-laravel/","author":null,"excerpt":"Немного о транзакциях Laravel, Lumen. Как и где применять на практике.","tags":["Linux","PHP","Lumen"],"coverImage":{"childImageSharp":{"fluid":{"base64":"data:image/jpeg;base64,/9j/2wBDABALDA4MChAODQ4SERATGCgaGBYWGDEjJR0oOjM9PDkzODdASFxOQERXRTc4UG1RV19iZ2hnPk1xeXBkeFxlZ2P/2wBDARESEhgVGC8aGi9jQjhCY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2P/wgARCAALABQDASIAAhEBAxEB/8QAGQAAAgMBAAAAAAAAAAAAAAAAAAQBAgMF/8QAFQEBAQAAAAAAAAAAAAAAAAAAAAH/2gAMAwEAAhADEAAAAehVNqINA//EABkQAAIDAQAAAAAAAAAAAAAAAAEDABESMf/aAAgBAQABBQKwIxepWYDpySSo9//EABQRAQAAAAAAAAAAAAAAAAAAABD/2gAIAQMBAT8BP//EABQRAQAAAAAAAAAAAAAAAAAAABD/2gAIAQIBAT8BP//EABsQAAIDAAMAAAAAAAAAAAAAAAABAhEhEEFh/9oACAEBAAY/AtZ52UlSJxepG8f/xAAaEAEBAAMBAQAAAAAAAAAAAAABEQAhMRBR/9oACAEBAAE/IY+FZlJubGAkmOBjc6ofMNKrU8v/2gAMAwEAAgADAAAAEKw//8QAFREBAQAAAAAAAAAAAAAAAAAAEBH/2gAIAQMBAT8Qp//EABURAQEAAAAAAAAAAAAAAAAAABAR/9oACAECAQE/EIf/xAAaEAEBAQADAQAAAAAAAAAAAAABEQAhMUFR/9oACAEBAAE/EAJIEL6vRo2UAeo/NGsZg1MNfVHOnmDM8GGXLf/Z","aspectRatio":1.8815331010452963,"src":"/static/e9acb1e90465a5f9a4fef8e7edba3f25/b4295/photo-1521623475836-87d82a22184f.jpg","srcSet":"/static/e9acb1e90465a5f9a4fef8e7edba3f25/127d5/photo-1521623475836-87d82a22184f.jpg 200w,\n/static/e9acb1e90465a5f9a4fef8e7edba3f25/7ef6a/photo-1521623475836-87d82a22184f.jpg 400w,\n/static/e9acb1e90465a5f9a4fef8e7edba3f25/b4295/photo-1521623475836-87d82a22184f.jpg 800w,\n/static/e9acb1e90465a5f9a4fef8e7edba3f25/487eb/photo-1521623475836-87d82a22184f.jpg 1080w","sizes":"(max-width: 800px) 100vw, 800px"}}}},"id":"37bddf4c-6fad-5b3e-b526-624df85d8142","html":"<p>В документации laravel на транзакции не так уж и много сказано. Там есть примеры кода обращений  к базе данных в пределах одного замыкания, но что делать, если нам нужно больше свободы? Давайте копнём глубже, что бы посмотреть, что происходит за кадром и какие инструменты мы можем использовать для работы с транзакциями.</p>\n<p><em>Данная статья ждала своей очереди на перевод года 4, надеюсь она и сейчас не потеряла своей актуальности. Оставить не переведённой её я не мог.</em></p>\n<h3>Что такое Транзакции</h3>\n<p>Вы возможно уже знаете, что это такое, тем не менее, давайте рассмотрим. Транзакции дают возможность безопасно выполнять набор запросов изменяющие базу данных (например update, insert). Безопасно, потому что вы можете  откатить все запросы сделанные в рамках транзакции в любое время их выполнения.</p>\n<p>Представим, что у нас есть приложение, которое позволяет регистрировать пользователя и создавать учётные  записи. Каждый пользователь может иметь несколько учётных записей связанных с ними.</p>\n<p><em>Стоит задача, во время регистрации пользователя обработать \"исключение\" если учётная запись была создана успешно, но пользователь из-за каких-то ошибок не смог создаться.</em></p>\n<p>Пример кода:</p>\n<div class=\"gatsby-highlight\" data-language=\"php\"><pre class=\"language-php\"><code class=\"language-php\">    <span class=\"token comment\">// Создание учётной записи</span>\n    <span class=\"token variable\">$newAcct</span> <span class=\"token operator\">=</span> Account<span class=\"token punctuation\">:</span><span class=\"token punctuation\">:</span><span class=\"token function\">create</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">[</span>\n        <span class=\"token single-quoted-string string\">'accountname'</span> <span class=\"token operator\">=</span><span class=\"token operator\">></span> Input<span class=\"token punctuation\">:</span><span class=\"token punctuation\">:</span><span class=\"token function\">get</span><span class=\"token punctuation\">(</span><span class=\"token single-quoted-string string\">'accountname'</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">,</span>\n    <span class=\"token punctuation\">]</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n    \n    <span class=\"token comment\">// Создание пользователя</span>\n    <span class=\"token variable\">$newUser</span> <span class=\"token operator\">=</span> User<span class=\"token punctuation\">:</span><span class=\"token punctuation\">:</span><span class=\"token function\">create</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">[</span>\n        <span class=\"token single-quoted-string string\">'username'</span> <span class=\"token operator\">=</span><span class=\"token operator\">></span> Input<span class=\"token punctuation\">:</span><span class=\"token punctuation\">:</span><span class=\"token function\">get</span><span class=\"token punctuation\">(</span><span class=\"token single-quoted-string string\">'username'</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">,</span>\n        <span class=\"token single-quoted-string string\">'account_id'</span> <span class=\"token operator\">=</span><span class=\"token operator\">></span> <span class=\"token variable\">$newAcct</span><span class=\"token operator\">-</span><span class=\"token operator\">></span><span class=\"token property\">id</span><span class=\"token punctuation\">,</span>\n    <span class=\"token punctuation\">]</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span></code></pre></div>\n<p>Тут две ситуации которые могут вызвать проблемы:</p>\n<h4>1. Учётная запись не была создана.</h4>\n<p>Если учетная запись не была создана то и id, необходимое для передачи пользователю для поля account_id мы не получили. В этом случае, учётная запись и пользователь не будет созданы, так что это не обязательно нарушение целостности данных, нам просто нужно обработать эту ситуацию (в коде выше это не показано).</p>\n<h4>2. Пользователь не был создан.</h4>\n<p>Если же учётная запись была создана, но создание пользователя не было, то мы сталкиваемся с некоторыми вопросами. Теперь у вас есть учётная запись но к ней не привязаны пользователи, мы имеем нарушение целостности данных в БД. Можно дописать код с различными проверками, удалять в ручную созданные данные, но это же не наш метод! Давайте просто используем транзакции.</p>\n<h3>Инструментарий транзакций</h3>\n<p>Транзакции предоставляют нам три \"инструмента\" для работы:</p>\n<ol>\n<li>Создание транзакции</li>\n<li>rollback (Откат транзакции) - Отмена всех запросов в рамках транзакции. Завершение транзакции.</li>\n<li>commit (Фиксация транзакции) - Выполнение всех запросов в рамках созданной транзакции, данные не будут затронуты, пока транзакция не будет зафиксирована. Завершение транзакции.</li>\n</ol>\n<p>Псевдокод, как мог бы выглядеть предыдущий код с транзакциями:</p>\n<div class=\"gatsby-highlight\" data-language=\"php\"><pre class=\"language-php\"><code class=\"language-php\">    <span class=\"token comment\">// Создание транзакции</span>\n    <span class=\"token function\">beginTransaction</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n    \n    <span class=\"token comment\">// Выполняем запросы</span>\n    <span class=\"token variable\">$acct</span> <span class=\"token operator\">=</span> <span class=\"token function\">createAccount</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n    <span class=\"token variable\">$user</span> <span class=\"token operator\">=</span> <span class=\"token function\">createUser</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n    \n    <span class=\"token comment\">// Если какой то из запросов вернул false то делаем откат</span>\n    <span class=\"token keyword\">if</span><span class=\"token punctuation\">(</span> <span class=\"token operator\">!</span><span class=\"token variable\">$acct</span> <span class=\"token operator\">||</span> <span class=\"token operator\">!</span><span class=\"token variable\">$user</span> <span class=\"token punctuation\">)</span>\n    <span class=\"token punctuation\">{</span>\n        <span class=\"token function\">rollbackTransaction</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n    <span class=\"token punctuation\">}</span> <span class=\"token keyword\">else</span> <span class=\"token punctuation\">{</span>\n        <span class=\"token comment\">// Иначе фиксируем изменения</span>\n        <span class=\"token function\">commitTransaction</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n    <span class=\"token punctuation\">}</span></code></pre></div>\n<h3>Простые транзакции. Laravel</h3>\n<p>Первый и простой способ выполнить транзакцию в Laravel - это разместить ваши запросы в функции-замыкании метода DB::transaction():</p>\n<div class=\"gatsby-highlight\" data-language=\"php\"><pre class=\"language-php\"><code class=\"language-php\">    <span class=\"token constant\">DB</span><span class=\"token punctuation\">:</span><span class=\"token punctuation\">:</span><span class=\"token function\">transaction</span><span class=\"token punctuation\">(</span><span class=\"token keyword\">function</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span>\n    <span class=\"token punctuation\">{</span>\n        <span class=\"token variable\">$newAcct</span> <span class=\"token operator\">=</span> Account<span class=\"token punctuation\">:</span><span class=\"token punctuation\">:</span><span class=\"token function\">create</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">[</span>\n            <span class=\"token single-quoted-string string\">'accountname'</span> <span class=\"token operator\">=</span><span class=\"token operator\">></span> Input<span class=\"token punctuation\">:</span><span class=\"token punctuation\">:</span><span class=\"token function\">get</span><span class=\"token punctuation\">(</span><span class=\"token single-quoted-string string\">'accountname'</span><span class=\"token punctuation\">)</span>\n        <span class=\"token punctuation\">]</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n    \n        <span class=\"token variable\">$newUser</span> <span class=\"token operator\">=</span> User<span class=\"token punctuation\">:</span><span class=\"token punctuation\">:</span><span class=\"token function\">create</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">[</span>\n            <span class=\"token single-quoted-string string\">'username'</span> <span class=\"token operator\">=</span><span class=\"token operator\">></span> Input<span class=\"token punctuation\">:</span><span class=\"token punctuation\">:</span><span class=\"token function\">get</span><span class=\"token punctuation\">(</span><span class=\"token single-quoted-string string\">'username'</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">,</span>\n            <span class=\"token single-quoted-string string\">'account_id'</span> <span class=\"token operator\">=</span><span class=\"token operator\">></span> <span class=\"token variable\">$newAcct</span><span class=\"token operator\">-</span><span class=\"token operator\">></span><span class=\"token property\">id</span><span class=\"token punctuation\">,</span>\n        <span class=\"token punctuation\">]</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n    <span class=\"token punctuation\">}</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span></code></pre></div>\n<p>Одна вещь, которая тут не очевидна - как этот метод знает, что нам нужно откатить или совершить транзакцию?</p>\n<p>Узнать это можно посмотрев <a href=\"https://github.com/laravel/framework/blob/2a3efbc9f0e9f123484d7a88046d50cff8685d25/src/Illuminate/Database/Concerns/ManagesTransactions.php#L20\">код фреймворка</a></p>\n<div class=\"gatsby-highlight\" data-language=\"php\"><pre class=\"language-php\"><code class=\"language-php\">    \t<span class=\"token keyword\">public</span> <span class=\"token keyword\">function</span> <span class=\"token function\">transaction</span><span class=\"token punctuation\">(</span>Closure <span class=\"token variable\">$callback</span><span class=\"token punctuation\">)</span>\n    \t<span class=\"token punctuation\">{</span>\n    \t\t<span class=\"token variable\">$this</span><span class=\"token operator\">-</span><span class=\"token operator\">></span><span class=\"token function\">beginTransaction</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n    \t\t<span class=\"token comment\">// We'll simply execute the given callback within a try / catch block</span>\n    \t\t<span class=\"token comment\">// and if we catch any exception we can rollback the transaction</span>\n    \t\t<span class=\"token comment\">// so that none of the changes are persisted to the database.</span>\n    \t\t<span class=\"token keyword\">try</span>\n    \t\t<span class=\"token punctuation\">{</span>\n    \t\t\t<span class=\"token variable\">$result</span> <span class=\"token operator\">=</span> <span class=\"token variable\">$callback</span><span class=\"token punctuation\">(</span><span class=\"token variable\">$this</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n    \t\t\t<span class=\"token variable\">$this</span><span class=\"token operator\">-</span><span class=\"token operator\">></span><span class=\"token function\">commit</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n    \t\t<span class=\"token punctuation\">}</span>\n    \t\t<span class=\"token comment\">// If we catch an exception, we will roll back so nothing gets messed</span>\n    \t\t<span class=\"token comment\">// up in the database. Then we'll re-throw the exception so it can</span>\n    \t\t<span class=\"token comment\">// be handled how the developer sees fit for their applications.</span>\n    \t\t<span class=\"token keyword\">catch</span> <span class=\"token punctuation\">(</span>\\<span class=\"token package\">Exception</span> <span class=\"token variable\">$e</span><span class=\"token punctuation\">)</span>\n    \t\t<span class=\"token punctuation\">{</span>\n    \t\t\t<span class=\"token variable\">$this</span><span class=\"token operator\">-</span><span class=\"token operator\">></span><span class=\"token function\">rollBack</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n    \t\t\t<span class=\"token keyword\">throw</span> <span class=\"token variable\">$e</span><span class=\"token punctuation\">;</span>\n    \t\t<span class=\"token punctuation\">}</span>\n    \t\t<span class=\"token keyword\">return</span> <span class=\"token variable\">$result</span><span class=\"token punctuation\">;</span>\n    \t<span class=\"token punctuation\">}</span></code></pre></div>\n<p>Тут всё работает очень просто, если в функции-замыкании брошено исключение любого рода, то транзакция откатывается назад. Это означает, что любая ошибка SQL выполнит откат транзакций. Так же мы можем и сами вызвать исключение, что приведёт к откату. Что-то вроде этого:</p>\n<div class=\"gatsby-highlight\" data-language=\"php\"><pre class=\"language-php\"><code class=\"language-php\">    <span class=\"token constant\">DB</span><span class=\"token punctuation\">:</span><span class=\"token punctuation\">:</span><span class=\"token function\">transaction</span><span class=\"token punctuation\">(</span><span class=\"token keyword\">function</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span>\n    <span class=\"token punctuation\">{</span>\n        <span class=\"token variable\">$newAcct</span> <span class=\"token operator\">=</span> Account<span class=\"token punctuation\">:</span><span class=\"token punctuation\">:</span><span class=\"token function\">create</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">[</span>\n            <span class=\"token single-quoted-string string\">'accountname'</span> <span class=\"token operator\">=</span><span class=\"token operator\">></span> Input<span class=\"token punctuation\">:</span><span class=\"token punctuation\">:</span><span class=\"token function\">get</span><span class=\"token punctuation\">(</span><span class=\"token single-quoted-string string\">'accountname'</span><span class=\"token punctuation\">)</span>\n        <span class=\"token punctuation\">]</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n    \n        <span class=\"token variable\">$newUser</span> <span class=\"token operator\">=</span> User<span class=\"token punctuation\">:</span><span class=\"token punctuation\">:</span><span class=\"token function\">create</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">[</span>\n            <span class=\"token single-quoted-string string\">'username'</span> <span class=\"token operator\">=</span><span class=\"token operator\">></span> Input<span class=\"token punctuation\">:</span><span class=\"token punctuation\">:</span><span class=\"token function\">get</span><span class=\"token punctuation\">(</span><span class=\"token single-quoted-string string\">'username'</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">,</span>\n            <span class=\"token single-quoted-string string\">'account_id'</span> <span class=\"token operator\">=</span><span class=\"token operator\">></span> <span class=\"token variable\">$newAcct</span><span class=\"token operator\">-</span><span class=\"token operator\">></span><span class=\"token property\">id</span><span class=\"token punctuation\">,</span>\n        <span class=\"token punctuation\">]</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n    \n        <span class=\"token keyword\">if</span><span class=\"token punctuation\">(</span> <span class=\"token operator\">!</span><span class=\"token variable\">$newUser</span> <span class=\"token punctuation\">)</span>\n        <span class=\"token punctuation\">{</span>\n            <span class=\"token keyword\">throw</span> <span class=\"token keyword\">new</span> <span class=\"token class-name\"><span class=\"token punctuation\">\\</span>Exception</span><span class=\"token punctuation\">(</span><span class=\"token single-quoted-string string\">'User not created for account'</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n        <span class=\"token punctuation\">}</span>\n    <span class=\"token punctuation\">}</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span></code></pre></div>\n<h3>Расширенные транзакции в Laravel</h3>\n<p>Недавно мне (автору оригинальной статьи) потребовался больший контроль над транзакциями. Create() методы выполняли проверку данных, бросая ValidationException если была проблема с валидностью. И если это исключение было поймано, сервер перенаправлял пользователя на страницу с сообщением об ошибках.</p>\n<div class=\"gatsby-highlight\" data-language=\"php\"><pre class=\"language-php\"><code class=\"language-php\">    <span class=\"token keyword\">try</span> <span class=\"token punctuation\">{</span>\n        <span class=\"token comment\">// Валидация и создание, если данные верны</span>\n        <span class=\"token variable\">$newAcct</span> <span class=\"token operator\">=</span> Account<span class=\"token punctuation\">:</span><span class=\"token punctuation\">:</span><span class=\"token function\">create</span><span class=\"token punctuation\">(</span> <span class=\"token punctuation\">[</span><span class=\"token single-quoted-string string\">'accountname'</span> <span class=\"token operator\">=</span><span class=\"token operator\">></span> Input<span class=\"token punctuation\">:</span><span class=\"token punctuation\">:</span><span class=\"token function\">get</span><span class=\"token punctuation\">(</span><span class=\"token single-quoted-string string\">'accountname'</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">]</span> <span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n    <span class=\"token punctuation\">}</span> <span class=\"token keyword\">catch</span><span class=\"token punctuation\">(</span>ValidationException <span class=\"token variable\">$e</span><span class=\"token punctuation\">)</span>\n    <span class=\"token punctuation\">{</span>\n        <span class=\"token comment\">// Редирект на страницу с ошибкой</span>\n        <span class=\"token keyword\">return</span> Redirect<span class=\"token punctuation\">:</span><span class=\"token punctuation\">:</span><span class=\"token function\">to</span><span class=\"token punctuation\">(</span><span class=\"token single-quoted-string string\">'/form'</span><span class=\"token punctuation\">)</span>\n            <span class=\"token operator\">-</span><span class=\"token operator\">></span><span class=\"token function\">withErrors</span><span class=\"token punctuation\">(</span> <span class=\"token variable\">$e</span><span class=\"token operator\">-</span><span class=\"token operator\">></span><span class=\"token function\">getErrors</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span> <span class=\"token punctuation\">)</span>\n            <span class=\"token operator\">-</span><span class=\"token operator\">></span><span class=\"token function\">withInput</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n    <span class=\"token punctuation\">}</span>\n    \n    <span class=\"token keyword\">try</span> <span class=\"token punctuation\">{</span>\n        <span class=\"token comment\">// Валидация и создание, если данные верны</span>\n        <span class=\"token variable\">$newUser</span> <span class=\"token operator\">=</span> User<span class=\"token punctuation\">:</span><span class=\"token punctuation\">:</span><span class=\"token function\">create</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">[</span>\n            <span class=\"token single-quoted-string string\">'username'</span> <span class=\"token operator\">=</span><span class=\"token operator\">></span> Input<span class=\"token punctuation\">:</span><span class=\"token punctuation\">:</span><span class=\"token function\">get</span><span class=\"token punctuation\">(</span><span class=\"token single-quoted-string string\">'username'</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">,</span>\n            <span class=\"token single-quoted-string string\">'account_id'</span> <span class=\"token operator\">=</span><span class=\"token operator\">></span> <span class=\"token variable\">$newAcct</span><span class=\"token operator\">-</span><span class=\"token operator\">></span><span class=\"token property\">id</span>\n        <span class=\"token punctuation\">]</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n    <span class=\"token punctuation\">}</span> <span class=\"token keyword\">catch</span><span class=\"token punctuation\">(</span>ValidationException <span class=\"token variable\">$e</span><span class=\"token punctuation\">)</span>\n    <span class=\"token punctuation\">{</span>\n        <span class=\"token comment\">// Редирект на страницу с ошибкой</span>\n        <span class=\"token keyword\">return</span> Redirect<span class=\"token punctuation\">:</span><span class=\"token punctuation\">:</span><span class=\"token function\">to</span><span class=\"token punctuation\">(</span><span class=\"token single-quoted-string string\">'/form'</span><span class=\"token punctuation\">)</span>\n            <span class=\"token operator\">-</span><span class=\"token operator\">></span><span class=\"token function\">withErrors</span><span class=\"token punctuation\">(</span> <span class=\"token variable\">$e</span><span class=\"token operator\">-</span><span class=\"token operator\">></span><span class=\"token function\">getErrors</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span> <span class=\"token punctuation\">)</span>\n            <span class=\"token operator\">-</span><span class=\"token operator\">></span><span class=\"token function\">withInput</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n    <span class=\"token punctuation\">}</span></code></pre></div>\n<p>Встаёт вопрос, как поместить это в замыкание, если ValidationException всегда ловятся? Размещение этого когда в замыкании DB::transaction() не верно, т.к. гарантированно, что он никогда не вызовет откат, если проверка не завершилась при создании аккаунта или юзера.</p>\n<p>Однако, более внимательно изучив документацию, мы видим, что можем вручную вызвать beginTransaction, rollback и commit!</p>\n<p>Главное, что сделать это очень просто:</p>\n<div class=\"gatsby-highlight\" data-language=\"php\"><pre class=\"language-php\"><code class=\"language-php\">    <span class=\"token comment\">// Старт транзакции!</span>\n    <span class=\"token constant\">DB</span><span class=\"token punctuation\">:</span><span class=\"token punctuation\">:</span><span class=\"token function\">beginTransaction</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n    \n    <span class=\"token keyword\">try</span> <span class=\"token punctuation\">{</span>\n        <span class=\"token comment\">// Валидация и создание, если данные верны</span>\n        <span class=\"token variable\">$newAcct</span> <span class=\"token operator\">=</span> Account<span class=\"token punctuation\">:</span><span class=\"token punctuation\">:</span><span class=\"token function\">create</span><span class=\"token punctuation\">(</span> <span class=\"token punctuation\">[</span><span class=\"token single-quoted-string string\">'accountname'</span> <span class=\"token operator\">=</span><span class=\"token operator\">></span> Input<span class=\"token punctuation\">:</span><span class=\"token punctuation\">:</span><span class=\"token function\">get</span><span class=\"token punctuation\">(</span><span class=\"token single-quoted-string string\">'accountname'</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">]</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n    <span class=\"token punctuation\">}</span> <span class=\"token keyword\">catch</span><span class=\"token punctuation\">(</span>ValidationException <span class=\"token variable\">$e</span><span class=\"token punctuation\">)</span>\n    <span class=\"token punctuation\">{</span>\n        <span class=\"token comment\">// Откат и редирект на страницу с ошибкой</span>\n        <span class=\"token constant\">DB</span><span class=\"token punctuation\">:</span><span class=\"token punctuation\">:</span><span class=\"token function\">rollback</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n        <span class=\"token keyword\">return</span> Redirect<span class=\"token punctuation\">:</span><span class=\"token punctuation\">:</span><span class=\"token function\">to</span><span class=\"token punctuation\">(</span><span class=\"token single-quoted-string string\">'/form'</span><span class=\"token punctuation\">)</span>\n            <span class=\"token operator\">-</span><span class=\"token operator\">></span><span class=\"token function\">withErrors</span><span class=\"token punctuation\">(</span> <span class=\"token variable\">$e</span><span class=\"token operator\">-</span><span class=\"token operator\">></span><span class=\"token function\">getErrors</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span> <span class=\"token punctuation\">)</span>\n            <span class=\"token operator\">-</span><span class=\"token operator\">></span><span class=\"token function\">withInput</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n    <span class=\"token punctuation\">}</span> <span class=\"token keyword\">catch</span><span class=\"token punctuation\">(</span>\\<span class=\"token package\">Exception</span> <span class=\"token variable\">$e</span><span class=\"token punctuation\">)</span>\n    <span class=\"token punctuation\">{</span>\n        <span class=\"token comment\">// Откат</span>\n        <span class=\"token constant\">DB</span><span class=\"token punctuation\">:</span><span class=\"token punctuation\">:</span><span class=\"token function\">rollback</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n        <span class=\"token keyword\">throw</span> <span class=\"token variable\">$e</span><span class=\"token punctuation\">;</span>\n    <span class=\"token punctuation\">}</span>\n    \n    <span class=\"token keyword\">try</span> <span class=\"token punctuation\">{</span>\n        <span class=\"token comment\">// Валидация и создание, если данные верны</span>\n        <span class=\"token variable\">$newUser</span> <span class=\"token operator\">=</span> User<span class=\"token punctuation\">:</span><span class=\"token punctuation\">:</span><span class=\"token function\">create</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">[</span>\n            <span class=\"token single-quoted-string string\">'username'</span> <span class=\"token operator\">=</span><span class=\"token operator\">></span> Input<span class=\"token punctuation\">:</span><span class=\"token punctuation\">:</span><span class=\"token function\">get</span><span class=\"token punctuation\">(</span><span class=\"token single-quoted-string string\">'username'</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">,</span>\n            <span class=\"token single-quoted-string string\">'account_id'</span> <span class=\"token operator\">=</span><span class=\"token operator\">></span> <span class=\"token variable\">$newAcct</span><span class=\"token operator\">-</span><span class=\"token operator\">></span><span class=\"token property\">id</span>\n        <span class=\"token punctuation\">]</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n    <span class=\"token punctuation\">}</span> <span class=\"token keyword\">catch</span><span class=\"token punctuation\">(</span>ValidationException <span class=\"token variable\">$e</span><span class=\"token punctuation\">)</span>\n    <span class=\"token punctuation\">{</span>\n        <span class=\"token comment\">// Откат и редирект на страницу с ошибкой</span>\n        <span class=\"token constant\">DB</span><span class=\"token punctuation\">:</span><span class=\"token punctuation\">:</span><span class=\"token function\">rollback</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n        <span class=\"token keyword\">return</span> Redirect<span class=\"token punctuation\">:</span><span class=\"token punctuation\">:</span><span class=\"token function\">to</span><span class=\"token punctuation\">(</span><span class=\"token single-quoted-string string\">'/form'</span><span class=\"token punctuation\">)</span>\n            <span class=\"token operator\">-</span><span class=\"token operator\">></span><span class=\"token function\">withErrors</span><span class=\"token punctuation\">(</span> <span class=\"token variable\">$e</span><span class=\"token operator\">-</span><span class=\"token operator\">></span><span class=\"token function\">getErrors</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span> <span class=\"token punctuation\">)</span>\n            <span class=\"token operator\">-</span><span class=\"token operator\">></span><span class=\"token function\">withInput</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n    <span class=\"token punctuation\">}</span> <span class=\"token keyword\">catch</span><span class=\"token punctuation\">(</span>\\<span class=\"token package\">Exception</span> <span class=\"token variable\">$e</span><span class=\"token punctuation\">)</span>\n    <span class=\"token punctuation\">{</span>\n        <span class=\"token comment\">// Откат</span>\n        <span class=\"token constant\">DB</span><span class=\"token punctuation\">:</span><span class=\"token punctuation\">:</span><span class=\"token function\">rollback</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n        <span class=\"token keyword\">throw</span> <span class=\"token variable\">$e</span><span class=\"token punctuation\">;</span>\n    <span class=\"token punctuation\">}</span>\n    \n    <span class=\"token comment\">// Если всё хорошо - фиксируем</span>\n    <span class=\"token constant\">DB</span><span class=\"token punctuation\">:</span><span class=\"token punctuation\">:</span><span class=\"token function\">commit</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span></code></pre></div>\n<p><strong>Обратите внимание</strong>, что на всякий случай ловится и общий Exception (upd: Актуально для версий 5.*), чтобы обеспечить целостность данных, если будет выброшено какое-либо другое исключение, отличное от ValidationException.</p>\n<p>То что нужно! Мы полностью контролируем транзакции с базами данных в Laravel!</p>\n<h3>Ссылки</h3>\n<p>Эта статья - вольный перевод <a href=\"http://fideloper.com/laravel-database-transactions\">http://fideloper.com/laravel-database-transactions</a></p>\n<p>Русская документация по транзакциям <a href=\"http://laravel.su/docs/5.4/database#database-transactions\">http://laravel.su/docs/5.4/database#database-transactions</a></p>\n<h3>Update</h3>\n<p>Кажется статья несколько устарела и нуждается в обновлении, возникает ряд вопросов почему \"так а не так\", но в целом полезная.</p>","excerpt":"В документации laravel на транзакции не так уж и много сказано. Там есть примеры кода обращений  к базе данных в пределах одного замыкания…"}},"pageContext":{"isCreatedByStatefulCreatePages":false,"type":"posts","next":{"frontmatter":{"path":"/12-polieznykh-mietodov-v-kolliektsiiakh-laravel","title":"12* полезных методов в коллекциях laravel","tags":["Linux","Collections"]},"fileAbsolutePath":"/srv/www/softroot.ru/src/posts/polieznykh-mietodov-v-kolliektsiiakh-laravel.md"},"previous":{"frontmatter":{"path":"/ustanovka-laravel","title":"Установка Laravel","tags":["Linux","Laravel"]},"fileAbsolutePath":"/srv/www/softroot.ru/src/posts/ustanovka-laravel.md"}}}