Thu Feb 13
Query a group of records based on parameters deep in a parent relation.
$files = \App\Models\File::whereHas('material', function(\Illuminate\Database\Eloquent\Builder $material) {
$material->whereHas('category', function(\Illuminate\Database\Eloquent\Builder $category) {
$category->whereHas('bucket', function(\Illuminate\Database\Eloquent\Builder $bucket) {
$bucket->where('path', 'vbs-2020-focus');
});
});
})->toSql();
Mon Feb 3
Mocking multiple overloads based on arguments.
$this->mock('overload:Stripe\Charge', function ($mock) {
$mock->shouldReceive('create')
->with(\Mockery::on(function ($argument) {
return is_array($argument) && isset($argument['source']) && $argument['source'] == 'card_expired';
}))
->times(1)
->andThrow(new \Stripe\Error\InvalidRequest("Source should be a valid card id", null)) // This relies on the try/catch logic in the Job
->getMock()
->shouldReceive('create')
->times(1)
->andReturn($this->getTestStripeResponse()); // Overload our instance with this default
});
We ignore our raised exception by you guessed it, a try/catch block.
try {
$this->withoutExceptionHandling()->artisan("subscriptions:process-remaining --day={$day} --no-progress")
->expectsOutput('4 subscription(s) found');
} catch(\Throwable $exception) {
}
\Event::assertDispatched(\App\Events\CardCharged::class, 3);
try {
$this->withoutExceptionHandling()->artisan("subscriptions:process-remaining --day={$day} --no-progress")
->expectsOutput('1 subscription(s) found');
} catch(\Throwable $exception) {
}
Wed Feb 2
Illuminate\Queue\MaxAttemptsExceededException
This stack trace shows the method call set at 5 maxTries:
Illuminate\Queue\MaxAttemptsExceededException: App\Jobs\PendingOrderTransferJob has been attempted too many times or run too long. The job may have previously timed out. in /home/forge/obr.rethinkgroup.org/vendor/laravel/framework/src/Illuminate/Queue/Worker.php:394
Stack trace:
#0 /home/forge/obr.rethinkgroup.org/vendor/laravel/framework/src/Illuminate/Queue/Worker.php(314): Illuminate\Queue\Worker->markJobAsFailedIfAlreadyExceedsMaxAttempts('redis:horizon', Object(Illuminate\Queue\Jobs\RedisJob), 5)
The failed job payload shows 5 attempts were made:
{"type":"job","timeout":null,"tags":["App\\Model\\PendingOrderStatus:1534"],"id":"3078","data":{"command":"O:32:\"App\\Jobs\\PendingOrderTransferJob\":8:{s:6:\"status\";O:45:\"Illuminate\\Contracts\\Database\\ModelIdentifier\":3:{s:5:\"class\";s:28:\"App\\Model\\PendingOrderStatus\";s:2:\"id\";i:1534;s:10:\"connection\";s:5:\"mysql\";}s:6:\"\u0000*\u0000job\";N;s:10:\"connection\";s:13:\"redis:horizon\";s:5:\"queue\";s:15:\"orders:transfer\";s:15:\"chainConnection\";N;s:10:\"chainQueue\";N;s:5:\"delay\";N;s:7:\"chained\";a:0:{}}","commandName":"App\\Jobs\\PendingOrderTransferJob"},"displayName":"App\\Jobs\\PendingOrderTransferJob","timeoutAt":null,"pushedAt":"1580851619.0033","maxTries":null,"job":"Illuminate\\Queue\\CallQueuedHandler@call","attempts":5}
Mon Dec 16
Reminder of JSON fields
$table->json('source_payload');
$table->string('order_id')->storedAs('source_payload->>"$.eCommerceOrderId"');
$table->string('user_id')->storedAs('source_payload->>"$.eCommerceCustomerId"');
$table->string('organization_id')->storedAs('source_payload->>"$.obrorgid"');
// See https://themsaid.com/laravel-mysql-json-colum-fast-lookup-20160709/
$table->index('order_id');
$table->index('user_id');
$table->index('organization_id');
SELECT
*, payload->>"$[0].eCommerceCustomerId" as `eCommerceCustomerId`
FROM
pendingOrderStatus
WHERE
payload->>"$[0].eCommerceCustomerId" = '16350';
Mon Nov 18
name
isn't a publicly accessible property facepalm.name
is allowed oddly enough but sorting isn't respected so my guess is Laravel can't find the property and tries to sort by the object instead.It's extremely off-putting to see it partially sort and have no fucking clue why it didn't fully sort as expected. I spent longer than I should've and hated myself when I found the answer.
return $categories->sortBy(function(\App\Classes\Uploads\Category $category) {
return $category->getName();
}, SORT_NATURAL);
Wed Oct 16
can
method is on the user as authorization always attaches to the current logged in userThe following specifies checking the sendReceipt()
method in the OrderPolicy
(new Actions\SendReceipt)->canSee(function ($request) {
return $request->user()->can('sendReceipt', \App\Models\Order::class);
})->canRun(function ($request, $order) {
return $request->user()->can('sendReceipt', \App\Models\Order::class);
}),
Thu Oct 10
How to generate EPUB documentation for Elixir v1.6
mix archive.uninstall phx_new-1.4.10
) or conflicts happen during the build processgit clone https://github.com/phoenixframework/phoenix.git
cd phoenix
git checkout v1.4 (or next completed)
mix deps.get
mix docs --formatter epub
git clone https://github.com/elixir-lang/elixir-lang.github.com.git
git clone https://github.com/elixir-lang/elixir.git
cd elixir
nano Makefile
#==> Documentation tasks
# DOCS_FORMAT = html
DOCS_FORMAT = epub
make docs
cp doc/elixir/Elixir.epub
Tue Oct 8
IEx testing a file
import_file("lib/knockin/tasks/stack_overflow_query.ex")
data = %Knockin.Tasks.StackOverflowQuery{}
Knockin.Tasks.StackOverflowQuery.get_base_url
Sort order
Collections
Enum - Set of algorithms for enumerating over enumerables
all?
- Returns true if supplied callback applies to all valuesany?
- Returns true if supplied callback applies to a single valuechunk_every
chunk_by
map_every
each
map
min
max
filter
reduce
sort
uniq
uniq_by
Pattern matching - allows us to match simple values, data structures, and even functions
Control structures
if
and unless
- if looks for truthy, unless is the inverse and defaults to falsecase
- match against multiple patterns. _ required in the event there is no match (like default in other languages but required, unlike others). Allows for guard clausescond
- Match conditions instead of values, akin to else if from other languageswith
- (Need to look this up)Tue Oct 8
nova:publish
as Nova updates via composer. It's easier, if using composer, to run the commands on update.Wed Oct 2
Structs
%Person{}
right for the first answer? I looked at the code, not the text to answer it.Pattern Matching
assert_raise MatchError, fn ->
[a, b] = [1, 2, 3]
end
koan "The pattern can make assertions about what it expects" do
assert match?([1, _second, _third], [1, 2, 3])
end
Functions
koan "Functions can have default argument values" do
assert repeat_again("Hello ") == "Hello Hello Hello Hello Hello "
assert repeat_again("Hello ", 2) == "Hello Hello "
end
koan "You can build anonymous functions out of any elixir expression by prefixing it with &" do
three_times = &[&1, &1, &1]
assert three_times.("foo") == ["foo", "foo", "foo"]
end
koan "You can pass functions around as arguments. Place an '&' before the name and state the arity" do
assert times_five_and_then(2, &square/1) == 100
end
Enums
koan "Elements can have a lot in common" do
assert Enum.all?([1, 2, 3], &less_than_five?/1) == true
assert Enum.all?([4, 6, 8], &less_than_five?/1) == false
end
koan "You three there, follow me!" do
assert Enum.take([1, 2, 3, 4, 5], 3) == [1, 2, 3]
end
koan "Zip-up in pairs!" do
letters = [:a, :b, :c]
numbers = [1, 2, 3]
assert Enum.zip(letters, numbers) == [a: 1, b: 2, c: 3]
end
koan "When you want to find that one pesky element" do
assert Enum.find([1, 2, 3, 4], &even?/1) == 2
end
Thu Oct 3
Processes
koan "You can ask a process to introduce itself" do
information = Process.info(self())
assert information[:status] == :running
end
Agents
GenServers
koan "Let's use the remaining functions in the external API" do
Laptop.start_link("EL!73")
{_, response} = Laptop.unlock("EL!73")
assert response == "Laptop unlocked!"
Laptop.change_password("EL!73", "Elixir")
{_, response} = Laptop.unlock("EL!73")
assert response == "Incorrect password!"
{_, response} = Laptop.owner_name()
assert response == "Jack Sparrow"
end
Protocols
Comprehensions
koan "A generator specifies how to extract values from a collection" do
collection = [["Hello","World"], ["Apple", "Pie"]]
assert (for [a, b] <- collection, do: "#{a} #{b}") == ["Hello World", "Apple Pie"]
end
koan "You can use multiple generators at once" do
assert (for x <- ["little", "big"], y <- ["dogs", "cats"], do: "#{x} #{y}") == ["little dogs", "little cats", "big dogs", "big cats"]
end
Fri Sep 27
Customize download file name using record information.
/**
* Get the actions available for the resource.
*
* @param \Illuminate\Http\Request $request
* @return array
*/
public function actions(Request $request)
{
$fileName = $this->getDownloadFileName($request);
return [
(new DownloadExcel)->withFilename($fileName)
->withWriterType(\Maatwebsite\Excel\Excel::CSV)
->withName('Download CSV')
->withHeadings()
->only('code')
->onlyOnIndex()
->withoutConfirmation(),
];
}
/**
* Get the filename for the DownloadExcel action.
*
* @param \Illuminate\Http\Request $request
* @return string
*/
private function getDownloadFileName(Request $request)
{
$result = 'codes-' . time() . '.csv';
try {
$batch = $request->findModelQuery()->getParent();
$result = \Str::slug($batch->codeType->name) . "-{$batch->id}-codes.csv";
} catch (\Exception $exception) {
}
return $result;
}
Mon Aug 12 2019
selectedBucket
, if you emit an event named selectedBucketChanged
you'll see the event emitted twice. I believe it's because there are life cycle events for any prop that are emitted for reactivity that I just happened to trample on.Tue Jul 30
Laravel streaming upload from one filesystem (local/legacy) to another (spaces).
$resource = \Storage::disk('legacy')->readStream($source);
$status = \Storage::disk($this->disk)->put($destination, $resource, 'public');
$sourceSize = \Storage::disk('legacy')->size($source);
$destinationSize = \Storage::disk($this->disk)->size($destination);
Wed Jul 31
cloud
doesn't really coerce down to spaces
or s3
../artisan convert:material-assets -d spaces --no-progress --reset
Thu Aug 1
Chrome overrides to enable Vue devtools.
Sources
tab.>>
and select Overrides
.+ Select folder for overrides
.Allow
.Page
under the sources tab to show the files for the page.Save for overrides
. This places the file in a site/folder
location.{}
to pretty print the javascript.devtools
and hit enter. productionTip: !1,
devtools: !1,
performance: !1,