tourze/wechat-work-push-bundle
Symfony bundle that wires WeChat Work (企业微信) message pushing into your PHP application. It ships autoconfigured services and settings so you can send application messages and notifications to users, departments, and tags with minimal setup, keeping push logic out of your business code.
This is a Symfony bundle (tourze/wechat-work-push-bundle), not a Laravel package — it wraps the WeChat Work / WeCom application message push API (corp id, agent id, secret, access_token lifecycle, and message/send). You can still use it in Laravel, but you are adopting it as a library and doing the wiring yourself.
Minimal path:
composer require tourze/wechat-work-push-bundle — pin the exact version (0.0.3) while it is pre-1.0.src/ before the README. The README is thin; the real contract is the push service class, its constructor dependencies (HTTP client, token provider/cache, credentials DTO), and DependencyInjection/Configuration.php, which is the authoritative list of config keys.*Extension.php / *Bundle.php — those only run under Symfony's kernel. In Laravel you register the underlying services in a ServiceProvider or resolve them with app()->bind().text (or better, textcard) message to one user, using credentials from config/services.php, an HTTP client from Illuminate\Support\Facades\Http, and a cache store backed by Cache::store('redis').// config/services.php
'wecom' => [
'corp_id' => env('WECOM_CORP_ID'),
'agent_id' => env('WECOM_AGENT_ID'),
'secret' => env('WECOM_SECRET'),
],
Wire the bundle's client once as a singleton keyed by agent, and inject it — do not construct it per request.
Treat the token as a singleton resource, not a per-call lookup. WeCom issues one active access_token per (corp, secret); fetching a new one invalidates the old. Your binding must cache the token (TTL ~7200s, minus a safety margin) in a shared store — Redis, not the array/file cache — so multiple PHP-FPM workers and queue workers share it. If the bundle exposes a token-storage interface, implement it over Laravel's Cache repository; that is the single most important integration point.
Wrap it in a Notification channel. The ergonomic Laravel shape is a WeComChannel implementing send($notifiable, Notification $notification), with toWeCom() returning a message DTO. That gives you Notification::route(), queuing, and per-user routing for free, and keeps the bundle's API surface isolated in one class.
public function send($notifiable, Notification $notification): void
{
$message = $notification->toWeCom($notifiable);
$this->client->send($message->toArray()); // bundle call
}
Send from queued jobs, with a rate limiter. WeCom enforces per-agent limits and daily quotas on app messages, and returns errcode 45009 when you exceed them. Put pushes on a dedicated queue with RateLimited middleware; a burst of alert emails converted to WeCom pushes will hit the cap fast.
Distinguish message types by intent. textcard (title, description, url) and template_card for actionable notifications that link back into your app; markdown for ops/alerting channels; text only for low-value chatter. news/mpnews are rarely worth the effort in transactional flows.
Multi-tenant: credentials from the database, not env. If you push on behalf of several WeCom corps, key a client registry by tenant id (singleton per tenant, or a factory with a bounded pool) and namespace the token cache key by corp+agent. Storing per-tenant secrets in config/ will not scale.
Handle the error contract centrally. WeCom returns HTTP 200 with a non-zero errcode. Map 42001/40014 (invalid/expired token) to a single cache-bust-and-retry, 45009 to backoff, and everything else to a domain exception carrying errcode + errmsg so the job can be marked failed with context. Cap retries at one for token errors.
vendor/tourze/wechat-work-push-bundle against the previous install before upgrading, pin the exact version in composer.json, and check whether the patch touched the constructor signature of the push service — 0.0.x patch bumps routinely do.final with no interfaces for the HTTP client or token store, you are stuck with whatever client it hardcodes (likely Symfony HttpClient, which is a separate dependency to install).errcode 81013 / 60020 usually means the recipient's userid isn't in the agent's 可见范围 or the agentid doesn't match the secret. This is a WeCom console fix, not a code fix.| (touser: "zhangsan|lisi", @all for everyone in scope). A silently missing recipient is usually a whitespace or casing error — the API may still return errcode 0 with invaliduser in the response body, so log the whole response.errcode/invaliduser/msgid in your logs, debugging is guesswork. msgid is also what you need for the message-status API.file store on multiple hosts), you will rotate tokens constantly and get intermittent 40014 across workers. Verify with a log line in the token store.How can I help you explore Laravel packages today?