Skip to content

Instantly share code, notes, and snippets.

@vianneychin
Created April 8, 2025 18:55
Show Gist options
  • Save vianneychin/a4297104d4cb6a00597021e9251c544c to your computer and use it in GitHub Desktop.
Save vianneychin/a4297104d4cb6a00597021e9251c544c to your computer and use it in GitHub Desktop.
Some of my favorite Laravel code that I've written recently:
<?php
// A custom upsert method that I've implemented that both handles mass insert in one query as opposed to many.
// The Laravel upsert only returns a boolean so I've added a custom flag that allows you to return the data that was just upserted.
/**
* Handles upserting CommentCollections with option to return upserted data
*
* @param array $collectionsToUpsert Array of comment collections data to upsert
* @param bool $returnUpsertedData Whether to return the upserted records
* @param int|null $projectId Project ID to filter results when returning data
* @return Exception|Collection|bool
*/
public static function handleUpsert(
array $collectionsToUpsert,
bool $returnUpsertedData = false,
int|null $projectId = null
): Exception | Collection | bool {
$upsertSuccessful = CommentCollection::upsert(
$collectionsToUpsert,
uniqueBy: ["post_id", "project_id", "user_id"],
update: [
"title",
"views_count",
"likes_count",
]
);
if ($upsertSuccessful && $returnUpsertedData) {
$postIds = array_column($collectionsToUpsert, 'post_id');
$collections = CommentCollection::whereIn('post_id', $postIds)
->where('project_id', $projectId)
->get();
return $collections;
}
return $upsertSuccessful;
}
<?php
// Example of some service providers I've written for external APIs for easy reusability.
namespace App\Services;
use App\Models\InstagramAccountPost;
use Exception;
use Illuminate\Database\Eloquent\Builder;
use Illuminate\Support\Facades\Http;
use InfluencerTools\User;
use Illuminate\Support\Str;
use Throwable;
class UserInstagramPostsService
{
private $instagramPostsLimit = 25;
public function __construct(private User $user) {}
/**
* @param array $keywords
* @param string|null $pullFromDate
* @return Builder|bool
* @throws Exception
* @throws Throwable
*/
public function storeInstagramPostsByKeyword(
array $keywords,
string $pullFromDate = null
) {
$nextPageToken = null;
do {
$response = $this->getPostData(nextCursor: $nextPageToken);
$posts = $response->data ?? [];
$nextPageToken = $response->paging->cursors->after ?? null;
$postsToUpsert = [];
if ($this->hasReachedPaginationThresholdFor($posts)) {
$nextPageToken = null;
}
foreach ($posts as $post) {
$postedAt = $this->convertToMySqlTimestamp($post->timestamp);
if ($pullFromDate && $postedAt < $pullFromDate) {
$nextPageToken = null;
break;
}
if ($this->captionContainsAnyKeyword($post->caption, $keywords)) {
$postsToUpsert[] = [
'post_id' => $post->id,
'caption' => $post->caption,
'posted_at' => $postedAt,
'comments_count' => $post->comments_count,
'video_views' => $post->media_views ?? null,
'likes_count' => $post->like_count,
'permalink' => $post->permalink,
'user_instagram_account_id' => $this->user->instagram->id
];
}
}
} while ($nextPageToken);
$instagramPosts = InstagramAccountPost::handleUpsert(
postsToUpsert: $postsToUpsert,
returnUpsertedQuery: true
);
return $instagramPosts;
}
public function getPostData($nextCursor = null)
{
$id = $this->user->instagram->profile_id;
$accessToken = $this->user->instagram->access_token;
// Skip check if user has a manually inputted instagram
if (!$this->user->instagram->accountIsManuallyAdded) {
throw new Exception('No access token found.');
}
$params = [
'fields' => 'id,caption,media_type,media_url,permalink,timestamp,comments_count,like_count,video_views',
'access_token' => $accessToken,
'limit' => $this->instagramPostsLimit
];
if ($nextCursor) {
$params['after'] = $nextCursor;
}
try {
$response = Http::get("https://graph.facebook.com/v13.0/{$id}/media", $params);
return $response->object();
} catch (Throwable $th) {
report($th);
}
}
/**
* @param string $caption
* @param array $keywords
* @return bool
*/
public function captionContainsAnyKeyword(string $caption, array $keywords): bool
{
return collect($keywords)->some(fn($keyword) => Str::contains(haystack: $caption, needles: $keyword));
}
/**
* @param string $timestamp
* @return string
*/
public function convertToMySqlTimestamp(string $timestamp): string
{
$date = new \DateTime($timestamp);
$date->setTimezone(new \DateTimeZone('America/Los_Angeles'));
return $date->format('Y-m-d H:i:s');
}
/**
* @param mixed $posts
* @return bool
*
* If we have 20 or less, then don't go to next page.
*/
public function hasReachedPaginationThresholdFor($posts)
{
return count($posts) < ($this->instagramPostsLimit - 5);
}
}
<?php
// Example query that I've built that is blazingly fast for live-time data changing with Vue/React. This is re-used in several places as well.
/**
* @param Project $project
* @return QueryBuilder
*
* @throws InvalidArgumentException
* @throws BindingResolutionException
*/
public function commentCollectionsQueryBuilder(): QueryBuilder
{
return DB::table('comment_collections')
->leftJoin('platform_comments', 'comment_collections.id', '=', 'platform_comments.comment_collection_id')
->leftJoin('platforms', 'comment_collections.platform_id', '=', 'platforms.id')
->leftJoin('preferences', 'platform_comments.preference_id', '=', 'preferences.id')
->where('comment_collections.project_id', '=', $this->id)
->select(
'comment_collections.id',
DB::raw('COUNT(CASE WHEN platform_comments.parent_id IS NULL THEN 1 END) as comments_count'),
DB::raw('COUNT(CASE WHEN platform_comments.parent_id IS NOT NULL THEN 1 END) as replies_count'),
'source',
'title',
'likes_count',
'views_count',
'platforms.slug as platform',
'live_comments_enabled_at',
'scheduled_per_days',
'scheduled_per_hours',
'scheduled_per_minutes',
'stop_updating_at',
DB::raw('CASE WHEN stop_updating_at IS NOT NULL AND stop_updating_at < NOW() THEN true ELSE false END as should_stop_updating'),
'is_disabled',
DB::raw('COUNT(CASE WHEN preferences.sentiment_type = "positive" THEN 1 END) as positive_count'),
DB::raw('COUNT(CASE WHEN preferences.sentiment_type = "negative" THEN 1 END) as negative_count'),
DB::raw('COUNT(CASE WHEN preferences.sentiment_type = "neutral" THEN 1 END) as neutral_count'),
)
->groupBy('comment_collections.id');
}
<?php
// Just some basic tests
namespace Tests\Support;
use Tests\TestCase;
class UserProfileTest extends TestCase
{
private AuthUserFactory $users;
public function tearDown(): void
{
$this->users->cleanup();
parent::tearDown();
}
public function setUp(): void
{
parent::setUp();
$this->users = new AuthUserFactory();
}
public function test_user_can_view_their_own_profile(): void
{
$this->be($this->users->regularUser);
$currentUserProfilePath = route(
name: 'profile',
parameters: [
'user' => $this->users->regularUser
],
absolute: false
);
$response = $this->get($currentUserProfilePath);
$response->assertStatus(200);
}
public function test_user_can_view_other_users_profile_in_same_referral_community(): void
{
$this->be($this->users->regularUser);
$viewOtherUserProfilePath = route(
name: 'user.profile',
parameters: [
'user' => $this->users->regularUserTwo
],
absolute: false
);
$response = $this->get($viewOtherUserProfilePath);
$response->assertStatus(200);
}
public function test_user_cannot_view_external_referral_user(): void
{
$this->be($this->users->regularUser);
$viewOtherUserProfilePath = route(
name: 'user.profile',
parameters: [
'user' => $this->users->externalReferralRegularUser
],
absolute: false
);
$response = $this->get($viewOtherUserProfilePath);
$response->assertStatus(403);
}
public function test_super_admin_can_view_any_profile(): void
{
// Test viewing internal referral community user profile
$this->be($this->users->superAdminUser);
$viewOtherUserProfilePath = route(
name: 'user.profile',
parameters: [
'user' => $this->users->regularUser
],
absolute: false
);
$response = $this->get($viewOtherUserProfilePath);
$response->assertStatus(200);
// Test viewing external referral community user profile
$this->be($this->users->superAdminUser);
$viewOtherUserProfilePath = route(
name: 'user.profile',
parameters: [
'user' => $this->users->externalReferralRegularUser
],
absolute: false
);
$response = $this->get($viewOtherUserProfilePath);
$response->assertStatus(200);
// Test viewing their own profile
$currentUserProfilePath = route(
name: 'profile',
parameters: [
'user' => $this->users->superAdminUser
],
absolute: false
);
$response = $this->get($currentUserProfilePath);
$response->assertStatus(200);
}
public function test_admin_user_cannot_view_external_referral_profile()
{
$this->be($this->users->adminUser);
$viewOtherUserProfilePath = route(
name: 'user.profile',
parameters: [
'user' => $this->users->externalReferralRegularUser
],
absolute: false
);
$response = $this->get($viewOtherUserProfilePath);
$response->assertStatus(403);
}
public function test_admin_can_view_internal_referral_profile()
{
$this->be($this->users->adminUser);
$viewOtherUserProfilePath = route(
name: 'user.profile',
parameters: [
'user' => $this->users->regularUser
],
absolute: false
);
$response = $this->get($viewOtherUserProfilePath);
$response->assertStatus(200);
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment