Created
April 7, 2025 17:30
-
-
Save Shahinyanm/19dd78a0143b43af8205edb748ea3a83 to your computer and use it in GitHub Desktop.
ARPM.php
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| 4. Task - Collection | |
| use Illuminate\Support\Collection; | |
| $employees = collect([ | |
| ['name' => 'John', 'city' => 'Dallas'], | |
| ['name' => 'Jane', 'city' => 'Austin'], | |
| ['name' => 'Jake', 'city' => 'Dallas'], | |
| ['name' => 'Jill', 'city' => 'Dallas'], | |
| ]); | |
| $offices = collect([ | |
| ['office' => 'Dallas HQ', 'city' => 'Dallas'], | |
| ['office' => 'Dallas South', 'city' => 'Dallas'], | |
| ['office' => 'Austin Branch', 'city' => 'Austin'], | |
| ]); | |
| $output = $offices | |
| ->groupBy('city') | |
| ->mapWithKeys(function ($cityOffices, $city) use ($employees) { | |
| $names = $employees | |
| ->where('city', $city) | |
| ->pluck('name') | |
| ->values(); | |
| $offices = $cityOffices->pluck('office')->mapWithKeys(function ($office) use ($names) { | |
| return [$office => $names->all()]; | |
| }); | |
| return [$city => $offices->all()]; | |
| }) | |
| ->toArray(); |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| 1 . And Task communication | |
| namespace App\Services; | |
| use Google_Client; | |
| use Google_Service_Sheets; | |
| use Google_Service_Sheets_BatchUpdateSpreadsheetRequest; | |
| use Google_Service_Sheets_ChartSpec; | |
| use Google_Service_Sheets_EmbeddedChart; | |
| use Google_Service_Sheets_EmbeddedObjectPosition; | |
| use Google_Service_Sheets_GridCoordinate; | |
| use Google_Service_Sheets_AddChartRequest; | |
| use Google_Service_Sheets_Spreadsheet; | |
| use Google_Service_Sheets_ValueRange; | |
| class CumulativeSumChartService | |
| { | |
| public function generateAndUpload(): string | |
| { | |
| $data = $this->generateData(); | |
| $sheetId = 0; | |
| $client = new Google_Client(); | |
| $client->setAuthConfig(storage_path('app/google/credentials.json')); | |
| $client->addScope(Google_Service_Sheets::SPREADSHEETS); | |
| $service = new Google_Service_Sheets($client); | |
| $spreadsheet = new Google_Service_Sheets_Spreadsheet([ | |
| 'properties' => ['title' => 'Cumulative Sum Chart'], | |
| ]); | |
| $spreadsheet = $service->spreadsheets->create($spreadsheet); | |
| $spreadsheetId = $spreadsheet->spreadsheetId; | |
| $values = collect($data)->map(function ($row, $index) { | |
| return array_merge(["Individual " . ($index + 1)], $row); | |
| })->prepend(array_merge(["Name"], range(1, 52))) | |
| ->toArray(); | |
| $body = new Google_Service_Sheets_ValueRange([ | |
| 'values' => $values | |
| ]); | |
| $service->spreadsheets_values->update( | |
| $spreadsheetId, | |
| 'A1', | |
| $body, | |
| ['valueInputOption' => 'RAW'] | |
| ); | |
| $this->addChart($service, $spreadsheetId, $sheetId); | |
| return "https://docs.google.com/spreadsheets/d/{$spreadsheetId}/edit"; | |
| } | |
| private function generateData(): array | |
| { | |
| return collect(range(1, 10))->map(function () { | |
| $row = []; | |
| $sum = 0; | |
| for ($i = 0; $i < 52; $i++) { | |
| $rand = mt_rand() / mt_getrandmax(); | |
| $sum += $rand; | |
| $row[] = round($sum, 4); | |
| } | |
| return $row; | |
| })->toArray(); | |
| } | |
| private function addChart(Google_Service_Sheets $service, string $spreadsheetId, int $sheetId): void | |
| { | |
| $chart = new Google_Service_Sheets_EmbeddedChart([ | |
| 'spec' => new Google_Service_Sheets_ChartSpec([ | |
| 'title' => 'Cumulative Sum over Weeks', | |
| 'basicChart' => [ | |
| 'chartType' => 'LINE', | |
| 'legendPosition' => 'RIGHT_LEGEND', | |
| 'axis' => [ | |
| ['position' => 'BOTTOM_AXIS', 'title' => 'Week'], | |
| ['position' => 'LEFT_AXIS', 'title' => 'Cumulative sum'], | |
| ], | |
| 'domains' => [[ | |
| 'domain' => [ | |
| 'sourceRange' => [ | |
| 'sources' => [[ | |
| 'sheetId' => $sheetId, | |
| 'startRowIndex' => 0, | |
| 'endRowIndex' => 1, | |
| 'startColumnIndex' => 1, | |
| 'endColumnIndex' => 53, | |
| ]], | |
| ], | |
| ], | |
| ]], | |
| 'series' => collect(range(0, 9))->map(function ($i) use ($sheetId) { | |
| return [ | |
| 'series' => [ | |
| 'sourceRange' => [ | |
| 'sources' => [[ | |
| 'sheetId' => $sheetId, | |
| 'startRowIndex' => $i + 1, | |
| 'endRowIndex' => $i + 2, | |
| 'startColumnIndex' => 1, | |
| 'endColumnIndex' => 53, | |
| ]], | |
| ], | |
| ], | |
| ]; | |
| })->toArray() | |
| ], | |
| ]), | |
| 'position' => new Google_Service_Sheets_EmbeddedObjectPosition([ | |
| 'overlayPosition' => [ | |
| 'anchorCell' => new Google_Service_Sheets_GridCoordinate([ | |
| 'sheetId' => $sheetId, | |
| 'rowIndex' => 15, | |
| 'columnIndex' => 0, | |
| ]), | |
| ], | |
| ]), | |
| ]); | |
| $request = new Google_Service_Sheets_BatchUpdateSpreadsheetRequest([ | |
| 'requests' => [ | |
| new Google_Service_Sheets_AddChartRequest(['chart' => $chart]), | |
| ] | |
| ]); | |
| $service->spreadsheets->batchUpdate($spreadsheetId, $request); | |
| } | |
| } | |
| namespace App\Console\Commands; | |
| use Illuminate\Console\Command; | |
| use App\Services\CumulativeSumChartService; | |
| class GenerateCumulativeChart extends Command | |
| { | |
| protected $signature = 'cumulative:generate-chart'; | |
| protected $description = 'Generate and upload cumulative sum chart to Google Sheets'; | |
| public function handle() | |
| { | |
| $url = app(CumulativeSumChartService::class)->generateAndUpload(); | |
| } | |
| } |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| 5. Explanation | |
| command('app:example-command') - > Command Name, will run as php artisan app:example-command | |
| withoutOverlapping() => Don't run the next until current is not finished | |
| hourly() => working each hour | |
| onOneServer() => If project running on a few servers (for example kubernetes)command will run only in one server | |
| runInBackground() => running async => don't blocks other commands | |
| a) Cache - > Laravel standard Facade, using Redis or other driver to keep cached data, caching for example result of query, configs and etc... | |
| Context=> Custom cache, keeping data in runtime through one request, using for keep for example timing variables or dependency injections | |
| b)$query->update() => doing multiple(batch) updating, don't triggering saving, saved events, but triggering updated, updating, working fast | |
| $model->update() => working thorough eloquent model and triggering, updating, updated, saving,saved | |
| $model->updateQuietly() => Like $query->update() without triggring updated and updating events | |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Second task | |
| use Illuminate\Support\Facades\DB; | |
| class OrderController extends Controller | |
| { | |
| public function index() | |
| { | |
| // 1. Eager load customer, items, and item.product | |
| $orders = Order::with(['customer', 'items.product']) | |
| ->withCount(['items as items_count']) // optimized count | |
| ->get(); | |
| // 2. Load all cart items (latest) in 1 query | |
| $cartItems = CartItem::select('order_id', DB::raw('MAX(created_at) as last_added_to_cart')) | |
| ->groupBy('order_id') | |
| ->pluck('last_added_to_cart', 'order_id'); | |
| // 3. Load completed orders once | |
| $completedOrders = Order::where('status', 'completed') | |
| ->get(['id', 'completed_at']) | |
| ->keyBy('id'); | |
| $orderData = $orders->map(function ($order) use ($cartItems, $completedOrders) { | |
| $totalAmount = $order->items->reduce(function ($sum, $item) { | |
| return $sum + $item->price * $item->quantity; | |
| }, 0); | |
| $completedOrder = $completedOrders->get($order->id); | |
| return [ | |
| 'order_id' => $order->id, | |
| 'customer_name' => $order->customer->name ?? 'N/A', | |
| 'total_amount' => $totalAmount, | |
| 'items_count' => $order->items_count, | |
| 'last_added_to_cart' => $cartItems[$order->id] ?? null, | |
| 'completed_order_exists' => $completedOrder !== null, | |
| 'created_at' => $order->created_at, | |
| 'completed_at' => $completedOrder->completed_at ?? null, | |
| ]; | |
| }); | |
| // 4. Sort in memory | |
| $sorted = $orderData->sortByDesc('completed_at')->values(); | |
| return view('orders.index', ['orders' => $sorted]); | |
| } | |
| } |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| 3. Third task - testing | |
| <?php | |
| namespace Tests\Unit\Services; | |
| use App\Jobs\ProcessProductImage; | |
| use App\Models\Product; | |
| use App\Services\SpreadsheetService; | |
| use Illuminate\Support\Facades\Queue; | |
| use Illuminate\Support\Facades\Validator; | |
| use Tests\TestCase; | |
| use Mockery; | |
| class SpreadsheetServiceTest extends TestCase | |
| { | |
| public function test_process_spreadsheet_creates_valid_products_and_dispatches_jobs() | |
| { | |
| Queue::fake(); | |
| $mockImporter = Mockery::mock(); | |
| $this->app->instance('importer', $mockImporter); | |
| $mockImporter->shouldReceive('import') | |
| ->once() | |
| ->andReturn([ | |
| ['product_code' => 'ABC123', 'quantity' => 10], | |
| ['product_code' => '', 'quantity' => 5], // Invalid: missing code | |
| ['product_code' => 'XYZ789', 'quantity' => 0], // Invalid: quantity < 1 | |
| ]); | |
| $service = new SpreadsheetService(); | |
| $service->processSpreadsheet('dummy/path/to/file.xlsx'); | |
| $this->assertDatabaseHas('products', [ | |
| 'code' => 'ABC123', | |
| 'quantity' => 10, | |
| ]); | |
| $this->assertDatabaseMissing('products', [ | |
| 'code' => 'XYZ789', | |
| ]); | |
| $this->assertEquals(1, Product::count()); | |
| Queue::assertPushed(ProcessProductImage::class, 1); | |
| } | |
| } |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment